reload configuration on SIGHUP

This commit is contained in:
Omar Polo 2021-02-04 13:23:15 +00:00
parent 1e3ef7ab4f
commit ca21e10043
7 changed files with 167 additions and 14 deletions

View File

@ -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

5
ex.c
View File

@ -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);

110
gmid.c
View File

@ -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)
@ -412,6 +417,47 @@ init_config(void)
conf.user = NULL;
}
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)
{
@ -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));
}
}

7
gmid.h
View File

@ -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

16
parse.y
View File

@ -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);

View File

@ -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;
}
}
}

28
utils.c
View File

@ -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;
}