summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLuke Bratch <luke@bratch.co.uk>2019-06-12 23:38:36 +0100
committerLuke Bratch <luke@bratch.co.uk>2019-06-12 23:38:36 +0100
commit6a2f7b87d4fb19f30f64ede4b18582eb366c8b7d (patch)
tree5400375fe286c33385762b741593d1e84ddffe11
parent3038e93b7e2e34296429a078b70205448c81e6cb (diff)
Allow reloading the configuration file at runtime using a BLABOUNCER command or by issuing the SIGHUP signal.
-rw-r--r--README15
-rw-r--r--TODO3
-rw-r--r--blabouncer.c35
-rw-r--r--blabouncer.conf.example2
-rw-r--r--config.c2
-rw-r--r--functions.c61
-rw-r--r--functions.h5
-rw-r--r--message.c28
8 files changed, 143 insertions, 8 deletions
diff --git a/README b/README
index c399a62..2a861c5 100644
--- a/README
+++ b/README
@@ -22,12 +22,27 @@ An example configuration file is provided named "blabouncer.conf".
If you don't specify one using "-c /path/to/configuration/file" then the example configuration one will be created for you in $HOME/.blabouncer/ when starting.
+Certain configuration options can be changed at runtime, either at any time, or by issuing a BLABOUNCER REHASH command or by sending SIGHUP to blabouncer.
+
+These options can be changed at any time as they are re-read when needed:
+ - nick2
+ - nick3
+ - password
+
+These options can be changed by issuing a BLABOUNCER REHASH command or by sending SIGHUP to blabouncer:
+ - replaymode
+ - replayseconds
+ - logging
+ - replaylogging
+ - debug
+
== Commands ==
Once connected to blabouncer with a client, you can use the following commands:
"BLABOUNCER REPLAY [[[[days:]hours:]minutes:]seconds]" (To replay a given length of time of replay log.)
"BLABOUNCER QUIT [quit message]" (To quit blabouncer, optionally sending [quit message] to the server.)
+"BLABOUNCER REHASH" (To reload settings from the configuration file, see above for details.)
Blabouncer commands are all prefixed with BLABOUNCER which you can usually send using "/QUOTE BLABOUNCER".
diff --git a/TODO b/TODO
index ff3bab2..081cb0c 100644
--- a/TODO
+++ b/TODO
@@ -7,5 +7,4 @@ Add various auto replay options:
Might need to #include <limits.h> in blabouncer.c to make some operating systems and/or compilers happy.
-Allow reloading the configuration file while running (at least for things like replayseconds, replaymode) - BLABOUNCER command and SIGHUP?
-
+Load all settings from configuration file at startup instead of referring to it for certain things (password/nick2/nick3).
diff --git a/blabouncer.c b/blabouncer.c
index 567de57..04a87ba 100644
--- a/blabouncer.c
+++ b/blabouncer.c
@@ -60,8 +60,6 @@
#define ECONFINT 1 // errno value if getconfint() failed
#define STDIN 0 // stdin is fd 0
-#define SIGINT 2 // SIGINT is signal 2
-#define SIGTERM 15 // SIGTERM is signal 15
// Various important limits - note that several related ones are defined in functions.h and structures.h
@@ -419,13 +417,15 @@ void dochat(int *serversockfd, int *clientsockfd, struct settings *settings) {
}
// Let's set up signal handling stuff here since we're about to enter The Big Loop (TM)
- // We'll handle SIGINT (Ctrl-C) and SIGTERM (default signal of `kill`)
+ // We'll handle SIGHUP (for rehashing), SIGINT (Ctrl-C), and SIGTERM (default signal of `kill`)
+ signal(SIGHUP, sighandler); // SIGHUP (1)
signal(SIGINT, sighandler); // SIGINT (2)
signal(SIGTERM, sighandler); // SIGTERM (15)
- // Block those two signals
+ // Block those signals
sigset_t sigset, oldset;
sigemptyset(&sigset);
+ sigaddset(&sigset, SIGHUP);
sigaddset(&sigset, SIGINT);
sigaddset(&sigset, SIGTERM);
sigprocmask(SIG_BLOCK, &sigset, &oldset);
@@ -460,9 +460,31 @@ void dochat(int *serversockfd, int *clientsockfd, struct settings *settings) {
if (errno == EINTR) {
// Signal caught, do signal handling
debugprint(DEBUG_CRIT, "signal '%d' happened, exiting!\n", signum);
- if (signum == SIGINT) {
+ if (signum == SIGHUP) { // REHASH requested
+ // TODO - This code is duplicated between here and BLABOUNCER REHASH handling
+ char outgoingmsg[MAXDATASIZE];
+ char failuremsg[MAXDATASIZE];
+ failuremsg[0] = '\0';
+
+ // Try to rehash...
+ if (!rehash(settings, failuremsg)) {
+ // ...or log and tell all clients if it failed
+ debugprint(DEBUG_CRIT, "SIGHUP REHASH failed: %s.\n", failuremsg);
+ if (!snprintf(outgoingmsg, MAXDATASIZE, "NOTICE %s :SIGHUP REHASH failed: %s.", ircdstate.ircnick, failuremsg)) {
+ debugprint(DEBUG_CRIT, "Error while preparing SIGHUP REHASH failure message response!\n");
+ outgoingmsg[0] = '\0';
+ }
+ sendtoallclients(clients, outgoingmsg, 0, settings);
+ } else {
+ // ...or tell all clients it worked
+ snprintf(outgoingmsg, MAXDATASIZE, "NOTICE %s :SIGUP REHASH complete!", ircdstate.ircnick);
+ sendtoallclients(clients, outgoingmsg, 0, settings);
+ }
+ // Then go back to the top of the loop
+ continue;
+ } else if (signum == SIGINT) { // Probably Ctrl+C
cleanexit(server_ssl, clients, 0, &ircdstate, settings, "SIGINT received");
- } else if (signum == SIGTERM) {
+ } else if (signum == SIGTERM) { // Probably `kill`
cleanexit(server_ssl, clients, 0, &ircdstate, settings, "SIGTERM received");
} else {
cleanexit(server_ssl, clients, 0, &ircdstate, settings, "Unexpected signal received");
@@ -806,6 +828,7 @@ int main(int argc, char *argv[]) {
}
// Populate settings from configuration file
+ // TODO - Try to share some/all of this code with the rehash() settings loading
// What is the auto replay mode?
if (!getconfstr("replaymode", settings.conffile, settings.replaymode)) {
diff --git a/blabouncer.conf.example b/blabouncer.conf.example
index f9c09bc..ebb2f23 100644
--- a/blabouncer.conf.example
+++ b/blabouncer.conf.example
@@ -7,6 +7,8 @@
#
# Shell expansion is not supported, so do not try and specify e.g.
# "~/.blabouncer/" or "$HOME/.blabouncer/", instead use "/home/foo/.blabouncer"
+#
+# Some settings can be reloaded at runtime, please refer to README for details.
nick = "blabounce"
nick2 = "bbounce2"
diff --git a/config.c b/config.c
index 94831d1..faa153a 100644
--- a/config.c
+++ b/config.c
@@ -191,6 +191,8 @@ int createconfigfile(char *filename) {
"#\n"
"# Shell expansion is not supported, so do not try and specify e.g.\n"
"# \"~/.blabouncer/\" or \"$HOME/.blabouncer/\", instead use \"/home/foo/.blabouncer\"\n"
+ "#\n"
+ "# Some settings can be reloaded at runtime, please refer to README for details.\n"
"\n"
"nick = \"blabounce\"\n"
"nick2 = \"bbounce2\"\n"
diff --git a/functions.c b/functions.c
index 5dbeb0c..abffb0b 100644
--- a/functions.c
+++ b/functions.c
@@ -990,3 +990,64 @@ void cleanexit(SSL *server_ssl, struct client *clients, int sourcefd, struct irc
exit(0);
}
+
+// Re-read the configuration file, setting 'failuremsg' to a failure message on failure.
+// Returns 1 on success or 0 on failure.
+int rehash(struct settings *settings, char *failuremsg) {
+ // TODO - Try to share some/all of this code with the initial main() settings loading
+
+ // What is the auto replay mode?
+ char oldreplaymode[MAXDATASIZE];
+ strcpy(oldreplaymode, settings->replaymode);
+ if (!getconfstr("replaymode", settings->conffile, settings->replaymode)) {
+ strcpy(settings->replaymode, oldreplaymode);
+ strcpy(failuremsg, "error getting 'replaymode' from configuration file");
+ return 0;
+ } else {
+ if (strcmp(settings->replaymode, "none") && strcmp(settings->replaymode, "time") && strcmp(settings->replaymode, "lastspoke")) {
+ strcpy(settings->replaymode, oldreplaymode);
+ strcpy(failuremsg, "replaymode in configuration file must be one of \"none\", \"time\", or \"lastspoke\"");
+ return 0;
+ }
+ }
+
+ // How many seconds of replay log should automatically be replayed - TODO - Can we do error checking on this?
+ int oldreplayseconds = settings->replayseconds;
+ settings->replayseconds = getconfint("replayseconds", settings->conffile);
+ if (errno == ECONFINT) {
+ settings->replayseconds = oldreplayseconds;
+ strcpy(failuremsg, "error getting 'replayseconds' from configuration file");
+ return 0;
+ }
+
+ // Is logging enabled?
+ int oldlogging = settings->logging;
+ settings->logging = getconfint("logging", settings->conffile);
+ if (errno == ECONFINT) {
+ settings->logging = oldlogging;
+ strcpy(failuremsg, "error getting 'logging' from configuration file");
+ return 0;
+ }
+
+ // Is replay logging enabled?
+ int oldreplaylogging = settings->replaylogging;
+ settings->replaylogging = getconfint("replaylogging", settings->conffile);
+ if (errno == ECONFINT) {
+ settings->replaylogging = oldreplaylogging;
+ strcpy(failuremsg, "error getting 'replaylogging' from configuration file");
+ return 0;
+ }
+
+ // Is debugging enabled?
+ int olddebug = debug;
+ debug = getconfint("debug", settings->conffile);
+ if (errno == ECONFINT) {
+ debug = olddebug;
+ strcpy(failuremsg, "error getting 'debug' from configuration file");
+ return 0;
+ }
+
+ // All is good, no failure message, return 1.
+ failuremsg[0] = '\0';
+ return 1;
+}
diff --git a/functions.h b/functions.h
index c0e90f8..07fdf09 100644
--- a/functions.h
+++ b/functions.h
@@ -35,6 +35,7 @@
#include "sockets.h"
#include "structures.h"
#include "replay.h"
+#include "config.h"
// getstdin() return codes
#define OK 0
@@ -156,4 +157,8 @@ void tryautonick(struct ircdstate *ircdstate);
// "sourcefd" of 0 means the request didn't come from a client
void cleanexit(SSL *server_ssl, struct client *clients, int sourcefd, struct ircdstate *ircdstate, struct settings *settings, char *quitmsg);
+// Re-read the configuration file, setting 'failuremsg' to a failure message on failure.
+// Returns 1 on success or 0 on failure.
+int rehash(struct settings *settings, char *failuremsg);
+
#endif
diff --git a/message.c b/message.c
index aa0dc1c..6e716e4 100644
--- a/message.c
+++ b/message.c
@@ -873,6 +873,8 @@ int processclientmessage(SSL *server_ssl, char *str, struct client *clients, int
sendtoclient(sourcefd, outgoingmsg, clients, settings, 0);
snprintf(outgoingmsg, MAXDATASIZE, "NOTICE %s :\"BLABOUNCER REPLAY [[[[days:]hours:]minutes:]seconds]\" (To replay a given length of time of replay log.)", ircdstate->ircnick);
sendtoclient(sourcefd, outgoingmsg, clients, settings, 0);
+ snprintf(outgoingmsg, MAXDATASIZE, "NOTICE %s :\"BLABOUNCER REHASH\" (To reload settings from the configuration file, see README for which settings can be reloaded.)", ircdstate->ircnick);
+ sendtoclient(sourcefd, outgoingmsg, clients, settings, 0);
snprintf(outgoingmsg, MAXDATASIZE, "NOTICE %s :\"BLABOUNCER QUIT [quit message]\" (To quit blabouncer, optionally sending [quit message] to the server.)", ircdstate->ircnick);
sendtoclient(sourcefd, outgoingmsg, clients, settings, 0);
@@ -1253,7 +1255,31 @@ int processclientmessage(SSL *server_ssl, char *str, struct client *clients, int
} else {
cleanexit(server_ssl, clients, sourcefd, ircdstate, settings, "");
}
+ // REHASH received, re-read the configuration file and let rehash() to the appropriate things
+ } else if (strncasecmp(tokens[1], "REHASH", strlen("REHASH")) == 0) {
+ debugprint(DEBUG_SOME, "Client BLABOUNCER REHASH found and it is: %s with length %zd! Attempting rehash...\n", tokens[1], strlen(tokens[1]));
+
+ // TODO - This code is duplicated between here and SIGHUP handling
+
+ char failuremsg[MAXDATASIZE];
+ failuremsg[0] = '\0';
+ // Try to rehash...
+ if (!rehash(settings, failuremsg)) {
+ // ...or log and tell client if it failed
+ debugprint(DEBUG_CRIT, "REHASH failed: %s.\n", failuremsg);
+ if (!snprintf(outgoingmsg, MAXDATASIZE, "NOTICE %s :REHASH failed: %s.", ircdstate->ircnick, failuremsg)) {
+ debugprint(DEBUG_CRIT, "Error while preparing REHASH failure message response!\n");
+ outgoingmsg[0] = '\0';
+ }
+ sendtoclient(sourcefd, outgoingmsg, clients, settings, 0);
+ } else {
+ // ...or tell all clients it worked
+ snprintf(outgoingmsg, MAXDATASIZE, "NOTICE %s :REHASH complete!", ircdstate->ircnick);
+ sendtoallclients(clients, outgoingmsg, 0, settings);
+ }
+
+ return 1;
// Unrecognised BLABOUNCER command received, send some help instructions
} else {
debugprint(DEBUG_SOME, "Client BLABOUNCER unrecognised command found and it is: %s with length %zd! Sending a help message.\n", tokens[1], strlen(tokens[1]));
@@ -1261,6 +1287,8 @@ int processclientmessage(SSL *server_ssl, char *str, struct client *clients, int
sendtoclient(sourcefd, outgoingmsg, clients, settings, 0);
snprintf(outgoingmsg, MAXDATASIZE, "NOTICE %s :\"BLABOUNCER REPLAY [[[[days:]hours:]minutes:]seconds]\" (To replay a given length of time of replay log.)", ircdstate->ircnick);
sendtoclient(sourcefd, outgoingmsg, clients, settings, 0);
+ snprintf(outgoingmsg, MAXDATASIZE, "NOTICE %s :\"BLABOUNCER REHASH\" (To reload settings from the configuration file, see README for which settings can be reloaded.)", ircdstate->ircnick);
+ sendtoclient(sourcefd, outgoingmsg, clients, settings, 0);
snprintf(outgoingmsg, MAXDATASIZE, "NOTICE %s :\"BLABOUNCER QUIT [quit message]\" (To quit blabouncer, optionally sending [quit message] to the server.)", ircdstate->ircnick);
sendtoclient(sourcefd, outgoingmsg, clients, settings, 0);
return 1;