From 968cee422ab1d61b4234127892d75f0497d8d8c2 Mon Sep 17 00:00:00 2001 From: Luke Bratch Date: Thu, 16 May 2019 20:59:51 +0100 Subject: Add a configurable base directory for things like logs, defaulting to $HOME/.blabouncer/. --- blabouncer.c | 31 +++++++++++++++++++++++++------ blabouncer.conf | 4 ++++ logging.c | 21 ++++++++++++++++++--- logging.h | 6 +++++- replay.c | 28 ++++++++++++++++++++-------- replay.h | 7 ++++--- 6 files changed, 76 insertions(+), 21 deletions(-) diff --git a/blabouncer.c b/blabouncer.c index 3f9004d..59cf8c1 100644 --- a/blabouncer.c +++ b/blabouncer.c @@ -16,6 +16,7 @@ // - Customise logging (disabling it, log file location) // - Alert when clients connect/authenticate/disconnect // - Perhaps rename arr_ssl and server_ssl since they may not even be OpenSSL sockets +// - Is it possible to replay JOINs/PARTs accurately? // // Example WHOIS reply: // BOUNCER-SERVER RECEIVED: :irc.tghost.co.uk 307 blabounce l_bratch :is identified for this nick @@ -35,6 +36,7 @@ #include #include #include +#include #include #include #include @@ -103,6 +105,7 @@ struct settings { char keyfile[PATH_MAX]; int clienttls; int servertls; + char basedir[PATH_MAX]; }; // Return index of requested client FD within arr_clients @@ -439,7 +442,7 @@ int doreplay(int sourcefd, int replayseconds, int arr_clients[], int arr_authed[ char outgoingmsg[MAXDATASIZE]; // Figure out how many lines to replay - int numlines = replaylines(replayseconds); + int numlines = replaylines(replayseconds, settings->basedir); printf("Replay log lines: '%d'.\n", numlines); if (numlines < 0) { @@ -453,7 +456,7 @@ int doreplay(int sourcefd, int replayseconds, int arr_clients[], int arr_authed[ // Replay those lines! for (int i = 0; i < numlines; i++) { - if (!readreplayline(replayseconds, i, outgoingmsg)) { + if (!readreplayline(replayseconds, i, outgoingmsg, settings->basedir)) { printf("Error requesting replay line.\n"); exit(1); } @@ -686,10 +689,10 @@ int processircmessage(SSL *server_ssl, int *clientsockfd, char *str, int source, sendtoallclients(clientsockfd, fdmax, arr_clients, str, sourcefd, arr_authed, arr_ssl, settings); // Write to replay log - writereplayline(str); + writereplayline(str, settings->basedir); // Write to normal log - logprivmsg(str, settings->ircnick); + logprivmsg(str, settings->ircnick, settings->basedir); return 1; } @@ -873,10 +876,10 @@ int processircmessage(SSL *server_ssl, int *clientsockfd, char *str, int source, sendtoallclients(clientsockfd, fdmax, arr_clients, outgoingmsg, sourcefd, arr_authed, arr_ssl, settings); // Write to replay log - writereplayline(outgoingmsg); + writereplayline(outgoingmsg, settings->basedir); // Write to normal log - logprivmsg(outgoingmsg, settings->ircnick); + logprivmsg(outgoingmsg, settings->ircnick, settings->basedir); return 1; } @@ -1438,6 +1441,22 @@ int main(int argc, char *argv[]) { } } + // Is the base directory set? If not, use the default. + if (!getconfstr("basedir", settings.conffile, settings.basedir)) { + snprintf(settings.basedir, PATH_MAX, "%s/.blabouncer/", getenv("HOME")); + } + + // Make sure the base directory exists + struct stat st = {0}; + if (stat(settings.basedir, &st) == -1) { + if (mkdir(settings.basedir, 0700)) { + printf("Error creating base directory '%s'.\n", settings.basedir); + exit(1); + } else { + printf("Created base directory '%s'.\n", settings.basedir); + } + } + // TODO: see if any of this can be shared (i.e. 1. avoid code duplication, and 2. see if variables can be shared between client/server sockets) // TODO: track fdmax - kind of doing this now with arr_clients and num_clients but might be pointlessly tracking both in some places (?) diff --git a/blabouncer.conf b/blabouncer.conf index d90d35b..cf9591b 100644 --- a/blabouncer.conf +++ b/blabouncer.conf @@ -37,3 +37,7 @@ certfile = "cert.pem" # Certificate key file # If clienttls = "0" then this need not be set keyfile = "key.pem" + +# Base directory (defaults to $HOME/.blabouncer/) +# Things such as the logs directory will be placed below this +#basedir = "/home/foo/.blabouncer/" diff --git a/logging.c b/logging.c index e0f5f1f..569a243 100644 --- a/logging.c +++ b/logging.c @@ -3,11 +3,13 @@ // Write the line 'str' to the relevant log file such as // '#channel.log' or 'nickname.log'. 'ournick' is our own // nick and is used to determine which log file to write to. +// 'basedir' is the directory in which the 'logs' directory +// will be created in which logs are to be written. // Expects a string in the format: // :from!bar@baz PRIVMSG to :hello world // With the ":foo!bar@baz "prefix being important. // Returns 1 on success or 0 on failure. -int logprivmsg(char *str, char *ournick) { +int logprivmsg(char *str, char *ournick, char *basedir) { // First, extract the "from" nick and the "to" nick or channel by splitting up the string // Track which space-separated token within this response we're on @@ -41,14 +43,27 @@ int logprivmsg(char *str, char *ournick) { char filename[MAXCHAR]; // If the message was sent to us, then log it in the sender's log file if (strncmp(tokens[2], ournick, strlen(tokens[0])) == 0) { - snprintf(filename, MAXCHAR, "%s.log", tokens[0]); + snprintf(filename, MAXCHAR, "%s/logs/%s.log", basedir, tokens[0]); } else { // Otherwise log it in the "to" log file - snprintf(filename, MAXCHAR, "%s.log", tokens[2]); + snprintf(filename, MAXCHAR, "%s/logs/%s.log", basedir, tokens[2]); } printf("logprivmsg(): Logging from '%s' to '%s' message '%s' in filename '%s'.\n", tokens[0], tokens[2], str, filename); + // Make sure the log directory exists + char logdir[PATH_MAX]; + snprintf(logdir, PATH_MAX, "%s/logs/", basedir); + struct stat st = {0}; + if (stat(logdir, &st) == -1) { + if (mkdir(logdir, 0700)) { + printf("Error creating log directory '%s'.\n", logdir); + exit(1); + } else { + printf("Created log directory '%s'.\n", logdir); + } + } + FILE *fp; char line[MAXCHAR]; diff --git a/logging.h b/logging.h index 289f348..726bb4d 100644 --- a/logging.h +++ b/logging.h @@ -4,6 +4,8 @@ #include #include #include +#include +#include #include "functions.h" @@ -17,10 +19,12 @@ // Write the line 'str' to the relevant log file such as // '#channel.log' or 'nickname.log'. 'ournick' is our own // nick and is used to determine which log file to write to. +// 'basedir' is the directory in which the 'logs' directory +// will be created in which logs are to be written. // Expects a string in the format: // :from!bar@baz PRIVMSG to :hello world // With the ":foo!bar@baz "prefix being important. // Returns 1 on success or 0 on failure. -int logprivmsg(char *str, char *ournick); +int logprivmsg(char *str, char *ournick, char *basedir); #endif diff --git a/replay.c b/replay.c index 3c2c920..a898a7b 100644 --- a/replay.c +++ b/replay.c @@ -137,10 +137,14 @@ void formattime(char *str) { } // Return the number of lines in the replay log since 'seconds' seconds ago, or -1 if there a problem. -int replaylines(int seconds) { +// 'basedir' is the directory in which to find 'replay.log'. +int replaylines(int seconds, char *basedir) { FILE *fp; char str[MAXCHAR]; - char* filename = "replay.log"; + char filename[PATH_MAX]; + + // Build path + snprintf(filename, PATH_MAX, "%s/replay.log", basedir); int numlines = 0; @@ -175,14 +179,18 @@ int replaylines(int seconds) { } // Set 'str' to the line in the log with a timestamp of greater than 'seconds' -// seconds ago, plus however many lines 'linenum' is set to. +// seconds ago, plus however many lines 'linenum' is set to. 'basedir' is the +// directory in which to find 'replay.log'. // Also modify the line to include a timestamp in the form "[HH:MM:SS]". // Returns 1 on success, or 0 on failure. // TODO - This is horribly inefficient since it re-reads the entire file each call, rewrite this! -int readreplayline(int seconds, int linenum, char *str) { +int readreplayline(int seconds, int linenum, char *str, char *basedir) { FILE *fp; char line[MAXCHAR]; - char* filename = "replay.log"; + char filename[PATH_MAX]; + + // Build path + snprintf(filename, PATH_MAX, "%s/replay.log", basedir); int count = 0; @@ -226,15 +234,19 @@ int readreplayline(int seconds, int linenum, char *str) { } // Write the line 'str' to the replay log file after prepending it with -// the current unixtime timestamp. +// the current unixtime timestamp. 'basedir' is the directory in which +// to write to 'replay.log'. // Expects a string in the format: // :from!bar@baz PRIVMSG to :hello world // With the ":foo!bar@baz "prefix being important. // Returns 1 on success or 0 on failure. -int writereplayline(char *str) { +int writereplayline(char *str, char *basedir) { FILE *fp; char line[MAXCHAR]; - char* filename = "replay.log"; + char filename[PATH_MAX]; + + // Build path + snprintf(filename, PATH_MAX, "%s/replay.log", basedir); int bytes = 0; diff --git a/replay.h b/replay.h index 7f1e331..983e05b 100644 --- a/replay.h +++ b/replay.h @@ -7,15 +7,16 @@ #include #include #include +#include #define MAXCHAR 1000 #define TIMELEN 11 // 32-bit unixtime is up to 10 characters (+1 for null char) // TODO - Make this Year 2038 proof #define TIMELENF 11 // [HH:MM:SS] = 10 characters + 1 for null char -int replaylines(int seconds); +int replaylines(int seconds, char *basedir); -int readreplayline(int seconds, int linenum, char *str); +int readreplayline(int seconds, int linenum, char *str, char *basedir); -int writereplayline(char *str); +int writereplayline(char *str, char *basedir); #endif -- cgit v1.2.3