forked from lda/telodendria
Prototype the configuration file parser.
Right now there's a nasty memory bug I need to fix. Will have to run this through valgrind.
This commit is contained in:
parent
0a101f0853
commit
cdd7808642
9 changed files with 515 additions and 32 deletions
|
@ -1,2 +1,4 @@
|
||||||
build
|
build
|
||||||
.env
|
.env
|
||||||
|
*.log
|
||||||
|
vgcore.*
|
||||||
|
|
13
contrib/development.conf
Normal file
13
contrib/development.conf
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
server-name "example.com";
|
||||||
|
chroot "/var/telodendria";
|
||||||
|
id "_telodendria" "_telodendria";
|
||||||
|
data-dir "./data";
|
||||||
|
federation "true";
|
||||||
|
registration "false";
|
||||||
|
log "stdout" {
|
||||||
|
level "debug";
|
||||||
|
timestampFormat "none";
|
||||||
|
color "true";
|
||||||
|
};
|
||||||
|
threads "4";
|
||||||
|
|
|
@ -13,18 +13,20 @@
|
||||||
# should go through and check.
|
# should go through and check.
|
||||||
#
|
#
|
||||||
|
|
||||||
# The address to listen on. You can specify multiple addresses by
|
# The address to listen on. It is recommended to listen on localhost,
|
||||||
# simply adding more values to this directive. It is recommended
|
# and then configure a reverse proxy # such as relayd(8) in front of
|
||||||
# to only listen on localhost, and then configure a reverse proxy
|
# it, because the server does not implement TLS.
|
||||||
# such as relayd(8) in front of it, because the server does not
|
|
||||||
# implement TLS.
|
|
||||||
#
|
#
|
||||||
# Also note that Telodendria doesn't provide multiple ports for
|
# Also note that Telodendria doesn't provide multiple ports for
|
||||||
# different things. All APIs are made available over the same port.
|
# different things. All APIs are made available over the same port.
|
||||||
# This works because Matrix allows the port configuration to be
|
# This works because Matrix allows the port configuration to be
|
||||||
# shared via .well-known/matrix/, which this server does properly
|
# shared via .well-known/matrix/, which this server does properly
|
||||||
# serve.
|
# serve.
|
||||||
listen "localhost:8008";
|
#
|
||||||
|
# The first parameter is the host name or IP address to listen on,
|
||||||
|
# and the second parameter is the port name or number. See the
|
||||||
|
# getaddrinfo() manual page for more information.
|
||||||
|
listen "localhost" "8008";
|
||||||
|
|
||||||
# Configure the domain name of your homeserver. Note that Matrix
|
# Configure the domain name of your homeserver. Note that Matrix
|
||||||
# servers cannot be migrated to other domains, so once this is set,
|
# servers cannot be migrated to other domains, so once this is set,
|
||||||
|
@ -55,7 +57,7 @@ id "_telodendria" "_telodendria";
|
||||||
# event information. Telodendria doesn't use a database; it uses a
|
# event information. Telodendria doesn't use a database; it uses a
|
||||||
# flat-file directory structure, sort of like how most SMTP servers
|
# flat-file directory structure, sort of like how most SMTP servers
|
||||||
# use Maildirs or mbox files.
|
# use Maildirs or mbox files.
|
||||||
data-dir "/data";
|
data-dir "./data";
|
||||||
|
|
||||||
# Whether to enable federation or not. Matrix is by default
|
# Whether to enable federation or not. Matrix is by default
|
||||||
# a federated protocol, but if you just want your own internal chat
|
# a federated protocol, but if you just want your own internal chat
|
||||||
|
@ -90,8 +92,8 @@ registration "false";
|
||||||
# configures the log file. If you're going to be running Telodendria
|
# configures the log file. If you're going to be running Telodendria
|
||||||
# in a chroot, the log file will have to live inside the chroot.
|
# in a chroot, the log file will have to live inside the chroot.
|
||||||
#
|
#
|
||||||
# Acceptable values here are "stdout", "stderr", or a log file.
|
# Acceptable values here are "stdout" or a log file.
|
||||||
log "/telodendria.log" {
|
log "./telodendria.log" {
|
||||||
# The level to log. This can be one of "error", "warning",
|
# The level to log. This can be one of "error", "warning",
|
||||||
# "task", "message", or "debug", with each level showing all
|
# "task", "message", or "debug", with each level showing all
|
||||||
# the levels above it as well. For example, "error" shows
|
# the levels above it as well. For example, "error" shows
|
14
src/Log.c
14
src/Log.c
|
@ -100,6 +100,12 @@ LogConfigFlagSet(LogConfig * config, int flags)
|
||||||
void
|
void
|
||||||
LogConfigFree(LogConfig * config)
|
LogConfigFree(LogConfig * config)
|
||||||
{
|
{
|
||||||
|
if (!config)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose(config->out);
|
||||||
free(config);
|
free(config);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -218,10 +224,6 @@ Log(LogConfig * config, LogLevel level, const char *msg,...)
|
||||||
|
|
||||||
pthread_mutex_lock(&config->lock);
|
pthread_mutex_lock(&config->lock);
|
||||||
|
|
||||||
for (i = 0; i < config->indent; i++)
|
|
||||||
{
|
|
||||||
fputc(' ', config->out);
|
|
||||||
}
|
|
||||||
|
|
||||||
doColor = LogConfigFlagGet(config, LOG_FLAG_COLOR)
|
doColor = LogConfigFlagGet(config, LOG_FLAG_COLOR)
|
||||||
&& isatty(fileno(config->out));
|
&& isatty(fileno(config->out));
|
||||||
|
@ -312,6 +314,10 @@ Log(LogConfig * config, LogLevel level, const char *msg,...)
|
||||||
}
|
}
|
||||||
|
|
||||||
fputc(' ', config->out);
|
fputc(' ', config->out);
|
||||||
|
for (i = 0; i < config->indent; i++)
|
||||||
|
{
|
||||||
|
fputc(' ', config->out);
|
||||||
|
}
|
||||||
|
|
||||||
va_start(argp, msg);
|
va_start(argp, msg);
|
||||||
vfprintf(config->out, msg, argp);
|
vfprintf(config->out, msg, argp);
|
||||||
|
|
|
@ -26,6 +26,8 @@
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include <TelodendriaConfig.h>
|
||||||
|
|
||||||
#include <Log.h>
|
#include <Log.h>
|
||||||
#include <HashMap.h>
|
#include <HashMap.h>
|
||||||
#include <Config.h>
|
#include <Config.h>
|
||||||
|
@ -83,10 +85,10 @@ main(int argc, char **argv)
|
||||||
ConfigParseResult *configParseResult = NULL;
|
ConfigParseResult *configParseResult = NULL;
|
||||||
HashMap *config = NULL;
|
HashMap *config = NULL;
|
||||||
|
|
||||||
lc = LogConfigCreate();
|
/* Program configuration */
|
||||||
|
TelodendriaConfig *tConfig = NULL;
|
||||||
|
|
||||||
/* TODO: Remove */
|
lc = LogConfigCreate();
|
||||||
LogConfigLevelSet(lc, LOG_DEBUG);
|
|
||||||
|
|
||||||
if (!lc)
|
if (!lc)
|
||||||
{
|
{
|
||||||
|
@ -147,15 +149,9 @@ main(int argc, char **argv)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Log(lc, LOG_MESSAGE, "Using configuration file '%s'.", configArg);
|
Log(lc, LOG_TASK, "Processing configuration file '%s'.", configArg);
|
||||||
|
|
||||||
Log(lc, LOG_DEBUG, "Executing ConfigParse()");
|
|
||||||
|
|
||||||
/* Read config here */
|
|
||||||
configParseResult = ConfigParse(configFile);
|
configParseResult = ConfigParse(configFile);
|
||||||
|
|
||||||
Log(lc, LOG_DEBUG, "Exitting ConfigParse()");
|
|
||||||
|
|
||||||
if (!ConfigParseResultOk(configParseResult))
|
if (!ConfigParseResultOk(configParseResult))
|
||||||
{
|
{
|
||||||
Log(lc, LOG_ERROR, "Syntax error on line %d.",
|
Log(lc, LOG_ERROR, "Syntax error on line %d.",
|
||||||
|
@ -167,18 +163,30 @@ main(int argc, char **argv)
|
||||||
config = ConfigParseResultGet(configParseResult);
|
config = ConfigParseResultGet(configParseResult);
|
||||||
ConfigParseResultFree(configParseResult);
|
ConfigParseResultFree(configParseResult);
|
||||||
|
|
||||||
Log(lc, LOG_DEBUG, "Closing configuration file.");
|
|
||||||
fclose(configFile);
|
fclose(configFile);
|
||||||
|
|
||||||
/* Configure log file */
|
tConfig = TelodendriaConfigParse(config, lc);
|
||||||
|
if (!tConfig)
|
||||||
|
{
|
||||||
|
exit = EXIT_FAILURE;
|
||||||
|
goto finish;
|
||||||
|
}
|
||||||
|
|
||||||
|
ConfigFree(config);
|
||||||
|
|
||||||
|
Log(lc, LOG_DEBUG, "Configuration:");
|
||||||
|
LogConfigIndent(lc);
|
||||||
|
Log(lc, LOG_DEBUG, "Listen On: %s:%s", tConfig->listenHost, tConfig->listenPort);
|
||||||
|
Log(lc, LOG_DEBUG, "Server Name: %s", tConfig->serverName);
|
||||||
|
Log(lc, LOG_DEBUG, "Chroot: %s", tConfig->chroot);
|
||||||
|
Log(lc, LOG_DEBUG, "Run As: %s:%s", tConfig->uid, tConfig->gid);
|
||||||
|
Log(lc, LOG_DEBUG, "Data Directory: %s", tConfig->dataDir);
|
||||||
|
Log(lc, LOG_DEBUG, "Threads: %d", tConfig->threads);
|
||||||
|
Log(lc, LOG_DEBUG, "Flags: %x", tConfig->flags);
|
||||||
|
LogConfigUnindent(lc);
|
||||||
|
|
||||||
finish:
|
finish:
|
||||||
if (config)
|
Log(lc, LOG_DEBUG, "Exiting with code '%d'.", exit);
|
||||||
{
|
TelodendriaConfigFree(tConfig);
|
||||||
Log(lc, LOG_DEBUG, "Freeing configuration structure.");
|
|
||||||
ConfigFree(config);
|
|
||||||
}
|
|
||||||
Log(lc, LOG_DEBUG, "Freeing log configuration and exiting with code '%d'.", exit);
|
|
||||||
LogConfigFree(lc);
|
|
||||||
return exit;
|
return exit;
|
||||||
}
|
}
|
||||||
|
|
317
src/TelodendriaConfig.c
Normal file
317
src/TelodendriaConfig.c
Normal file
|
@ -0,0 +1,317 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2022 Jordan Bancino <@jordan:bancino.net>
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person
|
||||||
|
* obtaining a copy of this software and associated documentation files
|
||||||
|
* (the "Software"), to deal in the Software without restriction,
|
||||||
|
* including without limitation the rights to use, copy, modify, merge,
|
||||||
|
* publish, distribute, sublicense, and/or sell copies of the Software,
|
||||||
|
* and to permit persons to whom the Software is furnished to do so,
|
||||||
|
* subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be
|
||||||
|
* included in all copies or portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
|
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||||
|
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||||
|
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||||
|
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
*/
|
||||||
|
#include <TelodendriaConfig.h>
|
||||||
|
#include <Config.h>
|
||||||
|
#include <HashMap.h>
|
||||||
|
#include <Log.h>
|
||||||
|
#include <Array.h>
|
||||||
|
#include <Util.h>
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
static int
|
||||||
|
IsInteger(char *str)
|
||||||
|
{
|
||||||
|
while (*str)
|
||||||
|
{
|
||||||
|
if (!isdigit(*str))
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
str++;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define GET_DIRECTIVE(name) \
|
||||||
|
directive = (ConfigDirective *) HashMapGet(config, name); \
|
||||||
|
if (!directive) { \
|
||||||
|
Log(lc, LOG_ERROR, "Missing required configuration directive: '%s'.", name); \
|
||||||
|
goto error; \
|
||||||
|
} \
|
||||||
|
children = ConfigChildrenGet(directive); \
|
||||||
|
value = ConfigValuesGet(directive); \
|
||||||
|
|
||||||
|
#define ASSERT_NO_CHILDREN(name) if (children) { \
|
||||||
|
Log(lc, LOG_ERROR, "Unexpected child values in directive: '%s'.", name); \
|
||||||
|
goto error; \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define ASSERT_VALUES(name, expected) if (ArraySize(value) != expected) { \
|
||||||
|
Log(lc, LOG_ERROR, \
|
||||||
|
"Wrong value count in directive '%s': got '%d', but expected '%d'.", \
|
||||||
|
name, ArraySize(value), expected); \
|
||||||
|
goto error; \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define COPY_VALUE(into, index) into = UtilStringDuplicate(ArrayGet(value, index))
|
||||||
|
|
||||||
|
TelodendriaConfig *
|
||||||
|
TelodendriaConfigParse(HashMap * config, LogConfig * lc)
|
||||||
|
{
|
||||||
|
TelodendriaConfig *tConfig;
|
||||||
|
|
||||||
|
ConfigDirective *directive;
|
||||||
|
Array *value;
|
||||||
|
HashMap *children;
|
||||||
|
|
||||||
|
if (!config || !lc)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
tConfig = calloc(1, sizeof(tConfig));
|
||||||
|
if (!tConfig)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
directive = (ConfigDirective *) HashMapGet(config, "listen");
|
||||||
|
children = ConfigChildrenGet(directive);
|
||||||
|
value = ConfigValuesGet(directive);
|
||||||
|
|
||||||
|
if (!directive)
|
||||||
|
{
|
||||||
|
Log(lc, LOG_WARNING, "No 'listen' directive specified; using defaults, which may change.");
|
||||||
|
tConfig->listenHost = UtilStringDuplicate("localhost");
|
||||||
|
tConfig->listenPort = UtilStringDuplicate("8008");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ASSERT_NO_CHILDREN("listen");
|
||||||
|
ASSERT_VALUES("listen", 2);
|
||||||
|
COPY_VALUE(tConfig->listenHost, 0);
|
||||||
|
COPY_VALUE(tConfig->listenPort, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
GET_DIRECTIVE("server-name");
|
||||||
|
ASSERT_NO_CHILDREN("server-name");
|
||||||
|
ASSERT_VALUES("server-name", 1);
|
||||||
|
COPY_VALUE(tConfig->serverName, 0);
|
||||||
|
|
||||||
|
GET_DIRECTIVE("chroot");
|
||||||
|
ASSERT_NO_CHILDREN("chroot");
|
||||||
|
ASSERT_VALUES("chroot", 1);
|
||||||
|
COPY_VALUE(tConfig->chroot, 0);
|
||||||
|
|
||||||
|
GET_DIRECTIVE("id");
|
||||||
|
ASSERT_NO_CHILDREN("id");
|
||||||
|
ASSERT_VALUES("id", 2);
|
||||||
|
COPY_VALUE(tConfig->uid, 0);
|
||||||
|
COPY_VALUE(tConfig->gid, 1);
|
||||||
|
|
||||||
|
GET_DIRECTIVE("data-dir");
|
||||||
|
ASSERT_NO_CHILDREN("data-dir");
|
||||||
|
ASSERT_VALUES("data-dir", 1);
|
||||||
|
COPY_VALUE(tConfig->dataDir, 0);
|
||||||
|
|
||||||
|
GET_DIRECTIVE("threads");
|
||||||
|
ASSERT_NO_CHILDREN("threads");
|
||||||
|
ASSERT_VALUES("threads", 1);
|
||||||
|
|
||||||
|
if (IsInteger(ArrayGet(value, 0)))
|
||||||
|
{
|
||||||
|
tConfig->threads = atoi(ArrayGet(value, 0));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Log(lc, LOG_ERROR,
|
||||||
|
"Expected integer for directive 'threads', "
|
||||||
|
"but got '%s'.", ArrayGet(value, 0));
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
GET_DIRECTIVE("federation");
|
||||||
|
ASSERT_NO_CHILDREN("federation");
|
||||||
|
ASSERT_VALUES("federation", 1);
|
||||||
|
|
||||||
|
if (strcmp(ArrayGet(value, 0), "true") == 0)
|
||||||
|
{
|
||||||
|
tConfig->flags |= TELODENDRIA_FEDERATION;
|
||||||
|
}
|
||||||
|
else if (strcmp(ArrayGet(value, 0), "false") != 0)
|
||||||
|
{
|
||||||
|
Log(lc, LOG_ERROR,
|
||||||
|
"Expected boolean value for directive 'federation', "
|
||||||
|
"but got '%s'.", ArrayGet(value, 0));
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
GET_DIRECTIVE("registration");
|
||||||
|
ASSERT_NO_CHILDREN("registration");
|
||||||
|
ASSERT_VALUES("registration", 1);
|
||||||
|
if (strcmp(ArrayGet(value, 0), "true") == 0)
|
||||||
|
{
|
||||||
|
tConfig->flags |= TELODENDRIA_REGISTRATION;
|
||||||
|
}
|
||||||
|
else if (strcmp(ArrayGet(value, 0), "false") != 0)
|
||||||
|
{
|
||||||
|
Log(lc, LOG_ERROR,
|
||||||
|
"Expected boolean value for directive 'registration', "
|
||||||
|
"but got '%s'.", ArrayGet(value, 0));
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
GET_DIRECTIVE("log");
|
||||||
|
ASSERT_VALUES("log", 1);
|
||||||
|
|
||||||
|
if (children)
|
||||||
|
{
|
||||||
|
ConfigDirective *cDirective;
|
||||||
|
char *cVal;
|
||||||
|
size_t size;
|
||||||
|
|
||||||
|
cDirective = HashMapGet(children, "level");
|
||||||
|
if (cDirective)
|
||||||
|
{
|
||||||
|
size = ArraySize(ConfigValuesGet(cDirective));
|
||||||
|
if (size > 1)
|
||||||
|
{
|
||||||
|
Log(lc, LOG_ERROR, "Expected 1 value for log.level, got %d.", size);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
cVal = ArrayGet(ConfigValuesGet(cDirective), 0);
|
||||||
|
if (strcmp(cVal, "message") == 0)
|
||||||
|
{
|
||||||
|
LogConfigLevelSet(lc, LOG_MESSAGE);
|
||||||
|
}
|
||||||
|
else if (strcmp(cVal, "debug") == 0)
|
||||||
|
{
|
||||||
|
LogConfigLevelSet(lc, LOG_DEBUG);
|
||||||
|
}
|
||||||
|
else if (strcmp(cVal, "task") == 0)
|
||||||
|
{
|
||||||
|
LogConfigLevelSet(lc, LOG_TASK);
|
||||||
|
}
|
||||||
|
else if (strcmp(cVal, "warning") == 0)
|
||||||
|
{
|
||||||
|
LogConfigLevelSet(lc, LOG_WARNING);
|
||||||
|
}
|
||||||
|
else if (strcmp(cVal, "error") == 0)
|
||||||
|
{
|
||||||
|
LogConfigLevelSet(lc, LOG_ERROR);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Log(lc, LOG_ERROR, "Invalid value for log.level: '%s'.", cVal);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cDirective = HashMapGet(children, "timestampFormat");
|
||||||
|
if (cDirective)
|
||||||
|
{
|
||||||
|
size = ArraySize(ConfigValuesGet(cDirective));
|
||||||
|
if (size > 1)
|
||||||
|
{
|
||||||
|
Log(lc, LOG_ERROR, "Expected 1 value for log.level, got %d.", size);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
cVal = ArrayGet(ConfigValuesGet(cDirective), 0);
|
||||||
|
|
||||||
|
if (strcmp(cVal, "none") == 0)
|
||||||
|
{
|
||||||
|
LogConfigTimeStampFormatSet(lc, NULL);
|
||||||
|
}
|
||||||
|
else if (strcmp(cVal, "default") != 0)
|
||||||
|
{
|
||||||
|
LogConfigTimeStampFormatSet(lc, UtilStringDuplicate(cVal));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cDirective = HashMapGet(children, "color");
|
||||||
|
if (cDirective)
|
||||||
|
{
|
||||||
|
size = ArraySize(ConfigValuesGet(cDirective));
|
||||||
|
if (size > 1)
|
||||||
|
{
|
||||||
|
Log(lc, LOG_ERROR, "Expected 1 value for log.level, got %d.", size);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
cVal = ArrayGet(ConfigValuesGet(cDirective), 0);
|
||||||
|
|
||||||
|
if (strcmp(cVal, "false") == 0)
|
||||||
|
{
|
||||||
|
LogConfigFlagClear(lc, LOG_FLAG_COLOR);
|
||||||
|
}
|
||||||
|
else if (strcmp(cVal, "true") != 0)
|
||||||
|
{
|
||||||
|
Log(lc, LOG_ERROR, "Expected boolean value for log.color, got '%s'.", cVal);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set the actual log output file last */
|
||||||
|
if (strcmp(ArrayGet(value, 0), "stdout") != 0)
|
||||||
|
{
|
||||||
|
FILE *out = fopen(ArrayGet(value, 0), "w");
|
||||||
|
|
||||||
|
if (!out)
|
||||||
|
{
|
||||||
|
Log(lc, LOG_ERROR, "Unable to open log file '%s' for writing.",
|
||||||
|
ArrayGet(value, 0));
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
Log(lc, LOG_DEBUG, "Redirecting output to '%s'.", ArrayGet(value, 0));
|
||||||
|
LogConfigOutputSet(lc, out);
|
||||||
|
}
|
||||||
|
|
||||||
|
tConfig->logConfig = lc;
|
||||||
|
return tConfig;
|
||||||
|
error:
|
||||||
|
TelodendriaConfigFree(tConfig);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
#undef GET_DIRECTIVE
|
||||||
|
#undef ASSERT_NO_CHILDREN
|
||||||
|
#undef ASSERT_VALUES
|
||||||
|
|
||||||
|
void
|
||||||
|
TelodendriaConfigFree(TelodendriaConfig * tConfig)
|
||||||
|
{
|
||||||
|
if (!tConfig)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
free(tConfig->listenHost);
|
||||||
|
free(tConfig->listenPort);
|
||||||
|
free(tConfig->serverName);
|
||||||
|
free(tConfig->chroot);
|
||||||
|
free(tConfig->uid);
|
||||||
|
free(tConfig->gid);
|
||||||
|
free(tConfig->dataDir);
|
||||||
|
|
||||||
|
LogConfigFree(tConfig->logConfig);
|
||||||
|
|
||||||
|
free(tConfig);
|
||||||
|
}
|
19
src/Util.c
19
src/Util.c
|
@ -24,6 +24,7 @@
|
||||||
#include <Util.h>
|
#include <Util.h>
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
#include <sys/time.h>
|
#include <sys/time.h>
|
||||||
|
|
||||||
long
|
long
|
||||||
|
@ -86,3 +87,21 @@ UtilUtf8Encode(unsigned long utf8)
|
||||||
|
|
||||||
return str;
|
return str;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
char *
|
||||||
|
UtilStringDuplicate(char *inStr)
|
||||||
|
{
|
||||||
|
size_t len;
|
||||||
|
char *outStr;
|
||||||
|
|
||||||
|
len = strlen(inStr);
|
||||||
|
outStr = malloc(len + 1); /* For the null terminator */
|
||||||
|
if (!outStr)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
strcpy(outStr, inStr);
|
||||||
|
|
||||||
|
return outStr;
|
||||||
|
}
|
||||||
|
|
100
src/include/TelodendriaConfig.h
Normal file
100
src/include/TelodendriaConfig.h
Normal file
|
@ -0,0 +1,100 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2022 Jordan Bancino <@jordan:bancino.net>
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person
|
||||||
|
* obtaining a copy of this software and associated documentation files
|
||||||
|
* (the "Software"), to deal in the Software without restriction,
|
||||||
|
* including without limitation the rights to use, copy, modify, merge,
|
||||||
|
* publish, distribute, sublicense, and/or sell copies of the Software,
|
||||||
|
* and to permit persons to whom the Software is furnished to do so,
|
||||||
|
* subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be
|
||||||
|
* included in all copies or portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
|
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||||
|
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||||
|
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||||
|
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* TelodendriaConfig.h: Validate and maintain the Telodendria server's
|
||||||
|
* configuration data. This API builds on the Config API to add
|
||||||
|
* Telodendria-specific parsing. It takes a fully parsed Config, and
|
||||||
|
* converts it into a TelodendriaConfig, which is more structured.
|
||||||
|
*/
|
||||||
|
#ifndef TELODENDRIA_TELODENDRIACONFIG_H
|
||||||
|
#define TELODENDRIA_TELODENDRIACONFIG_H
|
||||||
|
|
||||||
|
#include <Log.h>
|
||||||
|
#include <HashMap.h>
|
||||||
|
|
||||||
|
typedef enum TelodendriaConfigFlag
|
||||||
|
{
|
||||||
|
TELODENDRIA_FEDERATION = (1 << 0),
|
||||||
|
TELODENDRIA_REGISTRATION = (1 << 1)
|
||||||
|
} TelodendriaConfigFlag;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Since this configuration will live in memory for a long time, it is
|
||||||
|
* important that unused values are freed as soon as possible. Therefore,
|
||||||
|
* the TelodendriaConfig structure is not opaque; values are accessed
|
||||||
|
* directly, and they can be freed as the program wishes.
|
||||||
|
*
|
||||||
|
* NOTE: If you're going to free a value, make sure you set the pointer
|
||||||
|
* to NULL. TelodendriaConfigFree() will call free() on all values.
|
||||||
|
*/
|
||||||
|
typedef struct TelodendriaConfig
|
||||||
|
{
|
||||||
|
char *listenHost;
|
||||||
|
char *listenPort;
|
||||||
|
char *serverName;
|
||||||
|
char *chroot;
|
||||||
|
char *uid;
|
||||||
|
char *gid;
|
||||||
|
char *dataDir;
|
||||||
|
|
||||||
|
unsigned int flags;
|
||||||
|
unsigned int threads;
|
||||||
|
|
||||||
|
LogConfig *logConfig;
|
||||||
|
} TelodendriaConfig;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Parse a Config map, extracting the necessary values, validating them,
|
||||||
|
* and then adding them to a new TelodendriaConfig for future use by the
|
||||||
|
* program. All values are copied, so the Config hash map can be safely
|
||||||
|
* freed if this function succeeds.
|
||||||
|
*
|
||||||
|
* Params:
|
||||||
|
* (HashMap *) A hash map from ConfigParse(). This should be a map of
|
||||||
|
* ConfigDirectives.
|
||||||
|
* (LogConfig *) A working log configuration. Messages are written to
|
||||||
|
* this log as the parsing progresses, and this log is
|
||||||
|
* copied into the resulting TelodendriaConfig. It is
|
||||||
|
* also potentially modified by the configuration file's
|
||||||
|
* "log" block.
|
||||||
|
*
|
||||||
|
* Return: A TelodendriaConfig that is completely independent of the passed
|
||||||
|
* configuration hash map, or NULL if one or more required values is missing.
|
||||||
|
*/
|
||||||
|
extern TelodendriaConfig *
|
||||||
|
TelodendriaConfigParse(HashMap *, LogConfig *);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Free all of the memory allocated to the given configuration. This
|
||||||
|
* function unconditionally calls free() on all items in the structure,
|
||||||
|
* so make sure items that were already freed are NULL.
|
||||||
|
*
|
||||||
|
* Params:
|
||||||
|
* (TelodendriaConfig *) The configuration to free all the values for.
|
||||||
|
*/
|
||||||
|
extern void
|
||||||
|
TelodendriaConfigFree(TelodendriaConfig *);
|
||||||
|
|
||||||
|
#endif
|
|
@ -68,4 +68,20 @@ extern long
|
||||||
extern char *
|
extern char *
|
||||||
UtilUtf8Encode(unsigned long);
|
UtilUtf8Encode(unsigned long);
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Duplicate a null-terminated string, and return a new string on the
|
||||||
|
* heap.
|
||||||
|
*
|
||||||
|
* Params:
|
||||||
|
* (char *) The string to duplicate. It can be located anywhere on
|
||||||
|
* the heap or the stack.
|
||||||
|
*
|
||||||
|
* Return: A pointer to a null-terminated string on the heap. You must
|
||||||
|
* free() it when you're done with it. This may also return NULL if the
|
||||||
|
* call to malloc() fails.
|
||||||
|
*/
|
||||||
|
extern char *
|
||||||
|
UtilStringDuplicate(char *);
|
||||||
|
|
||||||
#endif /* TELODENDRIA_UTIL_H */
|
#endif /* TELODENDRIA_UTIL_H */
|
||||||
|
|
Loading…
Reference in a new issue