Commit 88ec8d10 authored by Marek Vavrusa's avatar Marek Vavrusa

Dynamic config reconfiguration started.

* Config is protected by RCU
* Logsystem reconfigures on-the-fly

Commit refs #541, #540.
parent be907e8f
......@@ -7,6 +7,8 @@
#include <unistd.h>
#include <errno.h>
#include <urcu.h>
#include "conf/conf.h"
#include "common.h"
......@@ -142,6 +144,19 @@ static void zone_free(conf_zone_t *zone)
/* Config processing. */
static void conf_update_hooks(conf_t *conf)
{
/*! \todo Selective hooks. */
node *n = 0;
conf->_touched = CONF_ALL;
WALK_LIST (n, conf->hooks) {
conf_hook_t *hook = (conf_hook_t*)n;
if ((hook->sections & conf->_touched) && hook->update) {
hook->update(conf);
}
}
}
static int conf_process(conf_t *conf)
{
// Normalize paths
......@@ -176,16 +191,6 @@ static int conf_process(conf_t *conf)
zone->db = dest;
}
/* Update hooks */
/*! \todo Selective hooks. */
conf->_touched = CONF_ALL;
WALK_LIST (n, conf->hooks) {
conf_hook_t *hook = (conf_hook_t*)n;
if ((hook->sections & conf->_touched) && hook->update) {
hook->update(conf);
}
}
return 0;
}
......@@ -248,39 +253,7 @@ void __attribute__ ((destructor)) conf_deinit()
}
}
/* API functions. */
conf_t *conf_new(const char* path)
{
conf_t *c = malloc(sizeof(conf_t));
memset(c, 0, sizeof(conf_t));
// Add path
if (path) {
c->filename = strdup(path);
}
// Initialize lists
init_list(&c->logs);
init_list(&c->ifaces);
init_list(&c->zones);
init_list(&c->hooks);
return c;
}
int conf_add_hook(conf_t * conf, int sections, int (*on_update)())
{
conf_hook_t *hook = malloc(sizeof(conf_hook_t));
hook->sections = sections;
hook->update = on_update;
add_tail(&conf->hooks, &hook->n);
++conf->hooks_count;
return 0;
}
int conf_parse(conf_t *conf)
static int conf_fparser(conf_t *conf)
{
if (!conf->filename) {
return -1;
......@@ -307,14 +280,10 @@ int conf_parse(conf_t *conf)
_parser_src = 0;
// }
pthread_mutex_unlock(&_parser_lock);
// Postprocess config
conf_process(conf);
return ret;
}
int conf_parse_str(conf_t *conf, const char* src)
static int conf_strparser(conf_t *conf, const char *src)
{
if (!src) {
return -1;
......@@ -346,10 +315,66 @@ int conf_parse_str(conf_t *conf, const char* src)
_parser_remaining = -1;
// }
pthread_mutex_unlock(&_parser_lock);
return ret;
}
// Postprocess config
/* API functions. */
conf_t *conf_new(const char* path)
{
conf_t *c = malloc(sizeof(conf_t));
memset(c, 0, sizeof(conf_t));
// Add path
if (path) {
c->filename = strdup(path);
}
// Initialize lists
init_list(&c->logs);
init_list(&c->ifaces);
init_list(&c->zones);
init_list(&c->hooks);
return c;
}
int conf_add_hook(conf_t * conf, int sections, int (*on_update)())
{
conf_hook_t *hook = malloc(sizeof(conf_hook_t));
hook->sections = sections;
hook->update = on_update;
add_tail(&conf->hooks, &hook->n);
++conf->hooks_count;
return 0;
}
int conf_parse(conf_t *conf)
{
/* Parse file. */
int ret = conf_fparser(conf);
/* Postprocess config. */
conf_process(conf);
/* Update hooks. */
conf_update_hooks(conf);
return ret;
}
int conf_parse_str(conf_t *conf, const char* src)
{
/* Parse config from string. */
int ret = conf_strparser(conf, src);
/* Postprocess config. */
conf_process(conf);
/* Update hooks */
conf_update_hooks(conf);
return ret;
}
......@@ -457,37 +482,51 @@ char* conf_find_default()
int conf_open(const char* path)
{
// Check existing config
if (!s_config) {
errno = ENOLINK; /* Link has been severed (POSIX.1) */
return -1;
}
// Check path
/* Check path. */
if (!path) {
errno = ENOENT; /* No such file or directory (POSIX.1) */
return -2;
}
// Check if exists
/* Check if exists. */
struct stat st;
if (stat(path, &st) != 0) {
errno = ENOENT; /* No such file or directory (POSIX.1) */
return -2;
}
// Truncate config
conf_truncate(s_config, 0);
/* Create new config. */
conf_t *nconf = conf_new(path);
// Parse config
s_config->filename = strdup(path);
int ret = conf_parse(s_config);
/* Parse config. */
int ret = conf_fparser(nconf);
if (ret != 0) {
conf_free(s_config);
s_config = 0;
conf_free(nconf);
return ret;
}
/* Replace current config. */
conf_t *oldconf = rcu_xchg_pointer(&s_config, nconf);
/* Copy hooks. */
node *n = 0;
WALK_LIST (n, oldconf->hooks) {
conf_hook_t *hook = (conf_hook_t*)n;
conf_add_hook(nconf, hook->sections, hook->update);
}
/* Postprocess config. */
conf_process(nconf);
/* Synchronize. */
synchronize_rcu();
/* Free old config. */
conf_free(oldconf);
/* Update hooks. */
conf_update_hooks(nconf);
return 0;
}
......
......@@ -15,6 +15,8 @@
#include <sys/types.h>
#include <sys/socket.h>
#include <urcu.h>
#include "dnslib/descriptor.h"
#include "lib/lists.h"
#include "other/log.h"
......@@ -268,6 +270,22 @@ static inline conf_t* conf() {
return s_config; // Inline for performance reasons.
}
/*!
* \brief Lock configuration for reading.
*
* \return Configuration context.
*/
static inline void conf_read_lock() {
rcu_read_lock();
}
/*!
* \brief Unlock configuration for reading.
*/
static inline void conf_read_unlock() {
rcu_read_unlock();
}
/*
* Utilities.
*/
......
......@@ -38,11 +38,10 @@ void help(int argc, char **argv)
}
int execute(const char *action, char **argv, int argc, pid_t pid, int verbose,
int force)
int force, const char *pidfile)
{
int valid_cmd = 0;
int rc = 0;
const char* pidfile = pid_filename();
if (strcmp(action, "start") == 0) {
// Check PID
......@@ -60,6 +59,9 @@ int execute(const char *action, char **argv, int argc, pid_t pid, int verbose,
}
}
// Lock configuration
conf_read_lock();
// Prepare command
const char *cfg = conf()->filename;
char* cmd = 0;
......@@ -68,13 +70,15 @@ int execute(const char *action, char **argv, int argc, pid_t pid, int verbose,
cfg ? "-c " : "", cfg ? cfg : "",
verbose ? "-v " : "", argc > 0 ? argv[0] : "");
// Unlock configuration
conf_read_unlock();
// Execute command
if ((rc = system(cmd)) < 0) {
pid_remove(pidfile);
rc = 1;
}
free(cmd);
}
if (strcmp(action, "stop") == 0) {
......@@ -103,7 +107,7 @@ int execute(const char *action, char **argv, int argc, pid_t pid, int verbose,
}
if (strcmp(action, "restart") == 0) {
valid_cmd = 1;
execute("stop", argv, argc, pid, verbose, force);
execute("stop", argv, argc, pid, verbose, force, pidfile);
int i = 0;
while((pid = pid_read(pidfile)) > 0) {
......@@ -124,7 +128,7 @@ int execute(const char *action, char **argv, int argc, pid_t pid, int verbose,
}
printf("Restarting server.\n");
rc = execute("start", argv, argc, -1, verbose, force);
rc = execute("start", argv, argc, -1, verbose, force, pidfile);
}
if (strcmp(action, "reload") == 0) {
......@@ -174,6 +178,9 @@ int execute(const char *action, char **argv, int argc, pid_t pid, int verbose,
// Check zone
valid_cmd = 1;
// Lock configuration
conf_read_lock();
// Generate databases for all zones
node *n = 0;
WALK_LIST(n, conf()->zones) {
......@@ -215,6 +222,9 @@ int execute(const char *action, char **argv, int argc, pid_t pid, int verbose,
}
free(cmd);
}
// Unlock configuration
conf_read_unlock();
}
if (!valid_cmd) {
fprintf(stderr, "Invalid command: '%s'\n", action);
......@@ -293,7 +303,7 @@ int main(int argc, char **argv)
}
// Fetch PID
const char* pidfile = pid_filename();
char* pidfile = pid_filename();
if (!pidfile) {
fprintf(stderr, "No configuration found, "
"please specify with '-c' parameter.\n");
......@@ -308,9 +318,10 @@ int main(int argc, char **argv)
// Execute action
int rc = execute(action, argv + optind + 1, argc - optind - 1,
pid, verbose, force);
pid, verbose, force, pidfile);
// Finish
free(pidfile);
log_close();
return rc;
}
......@@ -11,13 +11,19 @@
#include "other/log.h"
#include "conf/conf.h"
const char* pid_filename()
char* pid_filename()
{
conf_read_lock();
/* Read configuration. */
char* ret = 0;
if (conf()) {
return conf()->pidfile;
ret = strdup(conf()->pidfile);
}
return 0;
conf_read_unlock();
return ret;
}
pid_t pid_read(const char* fn)
......
......@@ -29,7 +29,7 @@ enum {
* \retval Filename of the database file.
* \retval NULL if not exists.
*/
const char* pid_filename();
char* pid_filename();
/*!
* \brief Read PID from given file.
......
......@@ -104,7 +104,9 @@ int main(int argc, char **argv)
}
// Initialize configuration
conf_read_lock();
conf_add_hook(conf(), CONF_LOG, log_conf_hook);
conf_read_unlock();
// Find implicit configuration file
char *default_fn = 0;
......@@ -129,9 +131,6 @@ int main(int argc, char **argv)
}
}
// Free default config filename if exists
free(default_fn);
// Verbose mode
if (verbose) {
int mask = LOG_MASK(LOG_INFO)|LOG_MASK(LOG_DEBUG);
......@@ -139,7 +138,7 @@ int main(int argc, char **argv)
}
// Create server instance
const char* pidfile = pid_filename();
char* pidfile = pid_filename();
server_t *server = server_create();
// Run server
......@@ -159,6 +158,13 @@ int main(int argc, char **argv)
}
}
// Change directory if daemonized
log_server_info("server: Started.\n");
if (daemonize) {
log_server_info("Server running as daemon.\n");
res = chdir("/");
}
// Setup signal blocking
sigset_t emptyset, blockset;
sigemptyset(&emptyset);
......@@ -179,13 +185,6 @@ int main(int argc, char **argv)
sigaction(SIGALRM, &sa, NULL); // Interrupt
sa.sa_flags = 0;
// Change directory if daemonized
log_server_info("server: Started.\n");
if (daemonize) {
log_server_info("Server running as daemon.\n");
res = chdir("/");
}
/* Run event loop. */
for(;;) {
int ret = evqueue_poll(evqueue(), &emptyset);
......@@ -197,17 +196,17 @@ int main(int argc, char **argv)
* event.
*/
if (sig_req_stop) {
debug_server("evqueue:"
debug_server("evqueue: "
"server stop requested\n");
sig_req_stop = 0;
server_stop(server);
break;
}
if (sig_req_reload) {
debug_server("evqueue:"
debug_server("evqueue: "
"reloading config\n");
sig_req_reload = 0;
//! \todo Reload config.
conf_open(config_fn);
}
}
......@@ -215,7 +214,7 @@ int main(int argc, char **argv)
if (ret > 0) {
event_t ev;
if (evqueue_get(evqueue(), &ev) == 0) {
debug_server("evqueue:"
debug_server("evqueue: "
"received new event\n");
if (ev.cb) {
ev.cb(&ev);
......@@ -250,10 +249,14 @@ int main(int argc, char **argv)
log_server_info("server: Shut down.\n");
log_close();
free(pidfile);
// Destroy event loop
evqueue_t *q = evqueue();
evqueue_free(&q);
// Free default config filename if exists
free(default_fn);
return res;
}
......@@ -26,6 +26,9 @@ typedef struct {
server_t *server_create()
{
/* Lock configuration. */
conf_read_lock();
/* Create interfaces. */
node *n = 0;
int ifaces_count = conf()->ifaces_count;
......@@ -85,6 +88,9 @@ server_t *server_create()
tcp_loaded++;
}
/* Unlock configuration. */
conf_read_unlock();
/* Evaluate if all sockets loaded. */
if ((tcp_loaded != ifaces_count) ||
(udp_loaded != ifaces_count)) {
......@@ -303,6 +309,9 @@ int server_start(server_t *server, const char **filenames, uint zones)
return -1;
}
/* Lock configuration. */
conf_read_lock();
debug_server("Starting server with %u zone files.\n",
zones + conf()->zones_count);
//stat
......@@ -342,6 +351,9 @@ int server_start(server_t *server, const char **filenames, uint zones)
}
}
/* Unlock configuration. */
conf_read_unlock();
// Load given zones
for (uint i = 0; i < zones; ++i) {
if (server_load_zone(server, "??", filenames[i]) == 0) {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment