diff options
-rw-r--r-- | ChangeLog | 4 | ||||
-rw-r--r-- | ex.c | 5 | ||||
-rw-r--r-- | gmid.c | 110 | ||||
-rw-r--r-- | gmid.h | 7 | ||||
-rw-r--r-- | parse.y | 16 | ||||
-rw-r--r-- | server.c | 11 | ||||
-rw-r--r-- | utils.c | 28 |
7 files changed, 167 insertions, 14 deletions
@@ -1,3 +1,7 @@ +2021-02-04 Omar Polo <op@omarpolo.com> + + * gmid.c (main): reload configuration on SIGHUP, without disconnecting the clients + 2021-02-02 Omar Polo <op@omarpolo.com> * server.c (handle_dirlist_head): print the header in the directory listing @@ -350,7 +350,7 @@ executor_main() err(1, "pledge"); #endif - for (;;) { + while (!hupped) { if (!recv_iri(exfd, &iri) || !recv_string(exfd, &spath) || !recv_string(exfd, &relpath) @@ -376,6 +376,9 @@ executor_main() free(chash); } + if (hupped) + _exit(0); + /* kill all process in my group. This means the listener and * every pending CGI script. */ kill(0, SIGINT); @@ -31,6 +31,8 @@ #include "gmid.h" +volatile sig_atomic_t hupped; + struct vhost hosts[HOSTSLEN]; int exfd, foreground, verbose, sock4, sock6; @@ -39,6 +41,7 @@ const char *config_path, *certs_dir, *hostname; struct conf conf; +struct tls_config *tlsconf; struct tls *ctx; void @@ -170,6 +173,8 @@ void sig_handler(int sig) { (void)sig; + + hupped = sig == SIGHUP; } void @@ -353,7 +358,6 @@ make_socket(int port, int family) void setup_tls(void) { - struct tls_config *tlsconf; struct vhost *h; if ((tlsconf = tls_config_new()) == NULL) @@ -371,7 +375,8 @@ setup_tls(void) /* we need to set something, then we can add how many key we want */ if (tls_config_set_keypair_file(tlsconf, hosts->cert, hosts->key)) - fatal("tls_config_set_keypair_file failed"); + fatal("tls_config_set_keypair_file failed for (%s, %s)", + hosts->cert, hosts->key); for (h = &hosts[1]; h->domain != NULL; ++h) { if (tls_config_add_keypair_file(tlsconf, h->cert, h->key) == -1) @@ -413,6 +418,47 @@ init_config(void) } void +free_config(void) +{ + struct vhost *h; + struct location *l; + + free(conf.chroot); + free(conf.user); + memset(&conf, 0, sizeof(conf)); + + for (h = hosts; h->domain != NULL; ++h) { + free((char*)h->domain); + free((char*)h->cert); + free((char*)h->key); + free((char*)h->dir); + free((char*)h->cgi); + + for (l = h->locations; l->match != NULL; ++l) { + free((char*)l->match); + free((char*)l->lang); + free((char*)l->default_mime); + free((char*)l->index); + } + } + memset(hosts, 0, sizeof(hosts)); + + tls_free(ctx); + tls_config_free(tlsconf); +} + +static void +wait_sighup(void) +{ + sigset_t mask; + int signo; + + sigemptyset(&mask); + sigaddset(&mask, SIGHUP); + sigwait(&mask, &signo); +} + +void drop_priv(void) { struct passwd *pw = NULL; @@ -490,16 +536,20 @@ serve(int argc, char **argv, int *p) fatal("fork: %s", strerror(errno)); case 0: /* child */ + setproctitle("listener"); close(p[0]); exfd = p[1]; drop_priv(); + unblock_signals(); listener_main(); _exit(0); default: /* parent */ + setproctitle("executor"); close(p[1]); exfd = p[0]; drop_priv(); + unblock_signals(); return executor_main(); } } @@ -509,6 +559,7 @@ main(int argc, char **argv) { int ch, p[2]; int conftest = 0, configless = 0; + int old_ipv6, old_port; init_config(); @@ -520,7 +571,7 @@ main(int argc, char **argv) break; case 'c': - config_path = optarg; + config_path = absolutify_path(optarg); break; case 'd': @@ -591,7 +642,7 @@ main(int argc, char **argv) signal(SIGINFO, sig_handler); #endif signal(SIGUSR2, sig_handler); - signal(SIGHUP, SIG_IGN); + signal(SIGHUP, sig_handler); if (!foreground && !configless) { if (daemon(1, 1) == -1) @@ -610,5 +661,54 @@ main(int argc, char **argv) if (conf.ipv6) sock6 = make_socket(conf.port, AF_INET6); - return serve(argc, argv, p); + if (configless) + return serve(argc, argv, p); + + /* wait a sighup and reload the daemon */ + for (;;) { + block_signals(); + + hupped = 0; + switch (fork()) { + case -1: + fatal("fork: %s", strerror(errno)); + case 0: + return serve(argc, argv, p); + } + + close(p[0]); + close(p[1]); + + unblock_signals(); + wait_sighup(); + LOGI("reloading configuration %s", config_path); + + old_ipv6 = conf.ipv6; + old_port = conf.port; + + free_config(); + init_config(); + parse_conf(config_path); + + if (old_port != conf.port) { + close(sock4); + close(sock6); + sock4 = -1; + sock6 = -1; + } + + if (sock6 != -1 && old_ipv6 != conf.ipv6) { + close(sock6); + sock6 = -1; + } + + if (sock4 == -1) + sock4 = make_socket(conf.port, AF_INET); + if (sock6 == -1 && conf.ipv6) + sock6 = make_socket(conf.port, AF_INET6); + + if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, + PF_UNSPEC, p) == -1) + fatal("socketpair: %s", strerror(errno)); + } } @@ -25,6 +25,7 @@ #include <dirent.h> #include <poll.h> +#include <signal.h> #include <stdio.h> #include <stdlib.h> #include <syslog.h> @@ -109,6 +110,8 @@ struct conf { extern struct conf conf; extern int exfd; +extern volatile sig_atomic_t hupped; + struct iri { char *schema; char *host; @@ -195,6 +198,7 @@ void load_vhosts(void); int make_socket(int, int); void setup_tls(void); void init_config(void); +void free_config(void); void drop_priv(void); void usage(const char*); @@ -250,9 +254,12 @@ int serialize_iri(struct iri*, char*, size_t); int puny_decode(const char*, char*, size_t, const char**); /* utils.c */ +void block_signals(void); +void unblock_signals(void); int starts_with(const char*, const char*); int ends_with(const char*, const char*); ssize_t filesize(int); char *absolutify_path(const char*); +char *xstrdup(const char*); #endif @@ -28,11 +28,10 @@ * int yydebug = 1; */ -struct vhost *host = &hosts[0]; -size_t ihost = 0; - -struct location *loc = &hosts[0].locations[0]; -size_t iloc = 0; +struct vhost *host; +size_t ihost; +struct location *loc; +size_t iloc; int goterror = 0; const char *config_path; @@ -85,7 +84,7 @@ vhosts : /* empty */ ; vhost : TSERVER TSTRING '{' servopts locations '}' { - host->locations[0].match = (char*)"*"; + host->locations[0].match = xstrdup("*"); host->domain = $2; if (strstr($2, "xn--") != NULL) { @@ -183,6 +182,11 @@ parse_portno(const char *p) void parse_conf(const char *path) { + host = &hosts[0]; + ihost = 0; + loc = &hosts[0].locations[0]; + iloc = 0; + config_path = path; if ((yyin = fopen(path, "r")) == NULL) fatal("cannot open config %s", path); @@ -906,8 +906,6 @@ loop(struct tls *ctx, int sock4, int sock6) struct client clients[MAX_USERS]; struct pollfd fds[MAX_USERS]; - connected_clients = 0; - for (i = 0; i < MAX_USERS; ++i) { fds[i].fd = -1; fds[i].events = POLLIN; @@ -952,5 +950,14 @@ loop(struct tls *ctx, int sock4, int sock6) else clients[i].state(&fds[i], &clients[i]); } + + if (hupped) { + if (connected_clients == 0) + return; + + fds[0].fd = -1; + if (sock6 != -1) + fds[1].fd = -1; + } } } @@ -19,6 +19,24 @@ #include "gmid.h" +static sigset_t set; + +void +block_signals(void) +{ + sigset_t new; + + sigemptyset(&new); + sigaddset(&new, SIGHUP); + sigprocmask(SIG_BLOCK, &new, &set); +} + +void +unblock_signals(void) +{ + sigprocmask(SIG_SETMASK, &set, NULL); +} + int starts_with(const char *str, const char *prefix) { @@ -80,3 +98,13 @@ absolutify_path(const char *path) free(wd); return r; } + +char * +xstrdup(const char *s) +{ + char *d; + + if ((d = strdup(s)) == NULL) + err(1, "strdup"); + return d; +} |