Fix config handling

This commit is contained in:
Tobias Reisinger 2020-11-12 21:58:01 +01:00
parent fad3d80f39
commit fca35ade9e
18 changed files with 125 additions and 139 deletions

1
.gitignore vendored
View file

@ -6,3 +6,4 @@ tests/testing/
include/sql/*.h include/sql/*.h
emgauwa-core.sqlite emgauwa-core.sqlite
vgcore.*

View file

@ -39,7 +39,7 @@ add_custom_target(sql
) )
add_custom_target(run add_custom_target(run
COMMAND ${CMAKE_BINARY_DIR}/core start COMMAND ${CMAKE_BINARY_DIR}/core
DEPENDS core DEPENDS core
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
) )
@ -56,24 +56,24 @@ add_custom_target(docs
) )
IF(CMAKE_BUILD_TYPE MATCHES Debug) IF(CMAKE_BUILD_TYPE MATCHES Debug)
message("debug mode") message(STATUS "loading debug targets")
add_custom_target(debug add_custom_target(debug
COMMAND gdb ${CMAKE_BINARY_DIR}/core COMMAND gdb ${CMAKE_BINARY_DIR}/core
DEPENDS core DEPENDS core
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
) )
add_custom_target(valgrind add_custom_target(valgrind
COMMAND valgrind -s ${CMAKE_BINARY_DIR}/core start COMMAND valgrind -s ${CMAKE_BINARY_DIR}/core
DEPENDS core DEPENDS core
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
) )
add_custom_target(valgrind-leak add_custom_target(valgrind-leak
COMMAND valgrind --leak-check=full --show-leak-kinds=all ${CMAKE_BINARY_DIR}/core start COMMAND valgrind --leak-check=full --show-leak-kinds=all ${CMAKE_BINARY_DIR}/core
DEPENDS core DEPENDS core
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
) )
add_custom_target(valgrind-callgrind add_custom_target(valgrind-callgrind
COMMAND valgrind --tool=callgrind ${CMAKE_BINARY_DIR}/core start COMMAND valgrind --tool=callgrind ${CMAKE_BINARY_DIR}/core
DEPENDS core DEPENDS core
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
) )

View file

@ -1,6 +1,6 @@
[core] [core]
server-port = 5000 server-port = 5000
database = core.sqlite database = emgauwa-core.sqlite
content-dir = /usr/share/webapps/emgauwa content-dir = /usr/share/webapps/emgauwa
not-found-file = 404.html not-found-file = 404.html
not-found-file-mime = text/html not-found-file-mime = text/html

13
include/cli.h Normal file
View file

@ -0,0 +1,13 @@
#ifndef CORE_CLI_H
#define CORE_CLI_H
typedef struct cli
{
char *config_path;
} cli_t;
void
cli_parse(int argc, const char **argv, config_t *config);
#endif /* CORE_CLI_H */

View file

@ -6,12 +6,6 @@
#include <mongoose.h> #include <mongoose.h>
#include <confini.h> #include <confini.h>
typedef enum
{
RUN_TYPE_START,
RUN_TYPE_INVALID,
} run_type_t;
typedef struct typedef struct
{ {
char *file; char *file;
@ -21,7 +15,6 @@ typedef struct
char *group; char *group;
int log_level; int log_level;
FILE *log_file; FILE *log_file;
run_type_t run_type;
uint16_t server_port; uint16_t server_port;
uint16_t discovery_port; uint16_t discovery_port;
uint16_t mqtt_port; uint16_t mqtt_port;
@ -33,7 +26,7 @@ typedef struct
struct mg_serve_http_opts http_server_opts; struct mg_serve_http_opts http_server_opts;
} config_t; } config_t;
extern config_t global_config; extern config_t *global_config;
void void
config_init(); config_init();
@ -42,7 +35,7 @@ void
config_free(); config_free();
void void
config_try_ini_files(config_t *config); config_load_string(char **holder, const char *value);
int int
config_load(IniDispatch *disp, void *config_void); config_load(IniDispatch *disp, void *config_void);

View file

@ -14,13 +14,6 @@
*/ */
#define MAX_NAME_LENGTH 128 #define MAX_NAME_LENGTH 128
/**
* @brief Maximum number of dbs for the databases for the MDB_env
*
* Used when calling mdb_env_set_maxdbs() in database_setup()
*/
#define MDB_MAXDBS 8
/** /**
* @brief How many milli seconds to wait until poll timeout in main loop * @brief How many milli seconds to wait until poll timeout in main loop
*/ */
@ -28,4 +21,6 @@
#define PIFACE_GPIO_BASE 200 #define PIFACE_GPIO_BASE 200
#define DEFAULT_CONFIG_PATH "emgauwa-core.ini"
#endif /* CORE_CONTANTS_H */ #endif /* CORE_CONTANTS_H */

View file

@ -3,14 +3,10 @@
#include <time.h> #include <time.h>
#include <config.h> #include <config.h>
#include <confini.h>
int int
helper_connect_tcp_server(char* host, uint16_t port); helper_connect_tcp_server(char* host, uint16_t port);
void
helper_parse_cli(int argc, const char **argv, config_t *config);
int int
helper_get_weekday(const struct tm *time_struct); helper_get_weekday(const struct tm *time_struct);

View file

@ -10,20 +10,20 @@
#include <version.h> #include <version.h>
static const char *const usage[] = { static const char *const usage[] = {
"core [options] [[--] args]",
"core [options]", "core [options]",
NULL, NULL,
}; };
void void
helper_parse_cli(int argc, const char **argv, config_t *config) cli_parse(int argc, const char **argv, config_t *config)
{ {
const char *config_file = NULL;
int version = 0; int version = 0;
struct argparse_option options[] = struct argparse_option options[] =
{ {
OPT_HELP(), OPT_HELP(),
OPT_GROUP("Basic options"), OPT_GROUP("Basic options"),
OPT_STRING('c', "config", &config->file, "path to config file", NULL, 0, OPT_NONEG), OPT_STRING('c', "config", &config_file, "path to config file", NULL, 0, OPT_NONEG),
OPT_BOOLEAN('v', "version", &version, "print version", NULL, 0, OPT_NONEG), OPT_BOOLEAN('v', "version", &version, "print version", NULL, 0, OPT_NONEG),
OPT_END(), OPT_END(),
}; };
@ -37,27 +37,15 @@ helper_parse_cli(int argc, const char **argv, config_t *config)
); );
argc = argparse_parse(&argparse, argc, argv); argc = argparse_parse(&argparse, argc, argv);
if(config_file)
{
config_load_string(&config->file, config_file);
}
if(version) if(version)
{ {
printf("%s\n", EMGAUWA_CORE_VERSION); printf("%s\n", EMGAUWA_CORE_VERSION);
exit(0); exit(0);
} }
if(argc == 1)
{
config->run_type = RUN_TYPE_INVALID;
if(strcmp(argv[0], "start") == 0)
{
config->run_type = RUN_TYPE_START;
return;
}
LOGGER_CRIT("bad action '%s' given ('start')\n", argv[0]);
exit(1);
}
else
{
LOGGER_CRIT("no action given ('start')\n");
exit(1);
}
return; return;
} }

View file

@ -1,10 +1,11 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <logger.h>
#include <config.h> #include <config.h>
#include <constants.h>
#include <logger.h>
config_t global_config; config_t *global_config;
#define CONFINI_IS_KEY(SECTION, KEY) \ #define CONFINI_IS_KEY(SECTION, KEY) \
@ -57,6 +58,7 @@ config_load_log_level(IniDispatch *disp, config_t *config)
return 0; return 0;
} }
LOGGER_WARNING("invalid log-level '%s'\n", disp->value); LOGGER_WARNING("invalid log-level '%s'\n", disp->value);
return 0; return 0;
} }
@ -77,8 +79,49 @@ config_load_log_file(IniDispatch *disp, config_t *config)
return 0; return 0;
} }
static void void
config_load_string(char **holder, char *value) config_init()
{
global_config = calloc(1, sizeof(config_t));
config_load_string(&global_config->file, DEFAULT_CONFIG_PATH);
global_config->discovery_port = 4421;
global_config->mqtt_port = 1885;
global_config->server_port = 5000;
global_config->log_level = LOG_DEBUG;
global_config->log_file = stdout;
global_config->user = NULL;
global_config->group = NULL;
config_load_string(&global_config->content_dir, ".");
config_load_string(&global_config->not_found_file, "404.html");
config_load_string(&global_config->not_found_file_type, "text/html");
config_load_string(&global_config->not_found_content, "404 - NOT FOUND");
config_load_string(&global_config->not_found_content_type, "text/plain");
}
void
config_free()
{
free(global_config->file);
free(global_config->include);
free(global_config->database);
free(global_config->user);
free(global_config->group);
free(global_config->content_dir);
free(global_config->not_found_file);
free(global_config->not_found_file_type);
free(global_config->not_found_content);
free(global_config->not_found_content_type);
free(global_config);
}
void
config_load_string(char **holder, const char *value)
{ {
if(*holder) if(*holder)
{ {
@ -93,50 +136,6 @@ config_load_string(char **holder, char *value)
*holder = new_holder; *holder = new_holder;
} }
void
config_init()
{
memset(&global_config, 0, sizeof(config_t));
global_config.discovery_port = 4421;
global_config.mqtt_port = 1885;
global_config.server_port = 5000;
global_config.log_level = LOG_INFO;
global_config.log_file = stdout;
global_config.user = NULL;
global_config.group = NULL;
config_load_string(&global_config.content_dir, ".");
config_load_string(&global_config.not_found_file, "404.html");
config_load_string(&global_config.not_found_file_type, "text/html");
config_load_string(&global_config.not_found_content, "404 - NOT FOUND");
config_load_string(&global_config.not_found_content_type, "text/plain");
}
void
config_free()
{
free(global_config.file);
free(global_config.include);
free(global_config.database);
free(global_config.user);
free(global_config.group);
free(global_config.content_dir);
free(global_config.not_found_file);
free(global_config.not_found_file_type);
free(global_config.not_found_content);
free(global_config.not_found_content_type);
}
void
config_try_ini_files(config_t *config)
{
(void)config;
}
int int
config_load(IniDispatch *disp, void *config_void) config_load(IniDispatch *disp, void *config_void)
{ {

View file

@ -13,7 +13,7 @@ static database_transaction_lock *transaction_lock;
void void
database_init() database_init()
{ {
int rc = sqlite3_open(global_config.database, &global_database); int rc = sqlite3_open(global_config->database, &global_database);
if(rc) if(rc)
{ {
@ -21,6 +21,8 @@ database_init()
exit(1); exit(1);
} }
LOGGER_DEBUG("Opened database %s\n", global_config->database);
database_migrate(); database_migrate();
sqlite3_exec(global_database, "PRAGMA foreign_keys = ON", 0, 0, 0); sqlite3_exec(global_database, "PRAGMA foreign_keys = ON", 0, 0, 0);

View file

@ -14,7 +14,7 @@ endpoint_func_index(struct mg_connection *nc, struct http_message *hm, endpoint_
response->status_code = 0; response->status_code = 0;
mg_serve_http(nc, hm, global_config.http_server_opts); mg_serve_http(nc, hm, global_config->http_server_opts);
} }
void void
@ -24,19 +24,19 @@ endpoint_func_not_found(struct mg_connection *nc, struct http_message *hm, endpo
(void)hm; (void)hm;
(void)nc; (void)nc;
if(access(global_config.not_found_file, R_OK) != -1) if(access(global_config->not_found_file, R_OK) != -1)
{ {
struct mg_str mime_type = mg_mk_str(global_config.not_found_file_type); struct mg_str mime_type = mg_mk_str(global_config->not_found_file_type);
response->status_code = 0; response->status_code = 0;
mg_http_serve_file(nc, hm, global_config.not_found_file, mime_type, mg_mk_str("")); mg_http_serve_file(nc, hm, global_config->not_found_file, mime_type, mg_mk_str(""));
} }
else else
{ {
LOGGER_DEBUG("404 file not found\n"); LOGGER_DEBUG("404 file not found\n");
response->status_code = 404; response->status_code = 404;
response->content_type = global_config.not_found_content_type; response->content_type = global_config->not_found_content_type;
response->content_length = strlen(global_config.not_found_content); response->content_length = strlen(global_config->not_found_content);
response->content = global_config.not_found_content; response->content = global_config->not_found_content;
response->alloced_content = false; response->alloced_content = false;
} }

View file

@ -122,7 +122,7 @@ api_v1_controllers_discover_PUT(struct mg_connection *nc, struct http_message *h
payload[0] = discover_server_port; payload[0] = discover_server_port;
LOGGER_DEBUG("sending udp broadcast\n"); LOGGER_DEBUG("sending udp broadcast\n");
if(send_udp_broadcast("255.255.255.255", global_config.discovery_port, payload, sizeof(payload)) < 0) if(send_udp_broadcast("255.255.255.255", global_config->discovery_port, payload, sizeof(payload)) < 0)
{ {
M_RESPONSE_TEXT_STATIC(LOGGER_ERR, response, 500, "the server failed to send discovery broadcast"); M_RESPONSE_TEXT_STATIC(LOGGER_ERR, response, 500, "the server failed to send discovery broadcast");
return; return;

View file

@ -23,6 +23,8 @@ api_v1_schedules_POST(struct mg_connection *nc, struct http_message *hm, endpoin
cJSON *json_name = cJSON_GetObjectItemCaseSensitive(json, "name"); cJSON *json_name = cJSON_GetObjectItemCaseSensitive(json, "name");
if(!cJSON_IsString(json_name) || (json_name->valuestring == NULL)) if(!cJSON_IsString(json_name) || (json_name->valuestring == NULL))
{ {
cJSON_Delete(json);
M_RESPONSE_400_NO_NAME(response); M_RESPONSE_400_NO_NAME(response);
return; return;
} }

View file

@ -17,16 +17,16 @@ static char*
add_extra_headers(char *extra_headers) add_extra_headers(char *extra_headers)
{ {
char *result; char *result;
size_t std_headers_len = strlen(global_config.http_server_opts.extra_headers); size_t std_headers_len = strlen(global_config->http_server_opts.extra_headers);
if(extra_headers == NULL) if(extra_headers == NULL)
{ {
result = malloc(sizeof(char) * (std_headers_len + 1)); result = malloc(sizeof(char) * (std_headers_len + 1));
strcpy(result, global_config.http_server_opts.extra_headers); strcpy(result, global_config->http_server_opts.extra_headers);
return result; return result;
} }
result = malloc(sizeof(char) * (std_headers_len + strlen(extra_headers) + 3)); result = malloc(sizeof(char) * (std_headers_len + strlen(extra_headers) + 3));
sprintf(result, "%s\r\n%s", global_config.http_server_opts.extra_headers, extra_headers); sprintf(result, "%s\r\n%s", global_config->http_server_opts.extra_headers, extra_headers);
return result; return result;
} }
@ -89,7 +89,7 @@ handle_http_request(struct mg_connection *nc, struct http_message *hm)
{ {
/* Normalize path - resolve "." and ".." (in-place). */ /* Normalize path - resolve "." and ".." (in-place). */
if (!mg_normalize_uri_path(&hm->uri, &hm->uri)) { if (!mg_normalize_uri_path(&hm->uri, &hm->uri)) {
mg_http_send_error(nc, 400, global_config.http_server_opts.extra_headers); mg_http_send_error(nc, 400, global_config->http_server_opts.extra_headers);
LOGGER_DEBUG("failed to normalize uri %.*s\n", hm->uri.len, hm->uri.p); LOGGER_DEBUG("failed to normalize uri %.*s\n", hm->uri.len, hm->uri.p);
return; return;
} }
@ -105,15 +105,15 @@ handle_http_request(struct mg_connection *nc, struct http_message *hm)
++request_file; ++request_file;
} }
char *request_file_path = malloc(sizeof(char) * (strlen(request_file) + strlen(global_config.content_dir) + 2)); char *request_file_path = malloc(sizeof(char) * (strlen(request_file) + strlen(global_config->content_dir) + 2));
sprintf(request_file_path, "%s/%s", global_config.content_dir, request_file); sprintf(request_file_path, "%s/%s", global_config->content_dir, request_file);
int access_result = access(request_file_path, R_OK); int access_result = access(request_file_path, R_OK);
free(request_file_path); free(request_file_path);
free(request_file_org); free(request_file_org);
if(access_result != -1) if(access_result != -1)
{ {
response.status_code = 0; response.status_code = 0;
mg_serve_http(nc, hm, global_config.http_server_opts); mg_serve_http(nc, hm, global_config->http_server_opts);
LOGGER_DEBUG("serving %.*s\n", hm->uri.len, hm->uri.p); LOGGER_DEBUG("serving %.*s\n", hm->uri.len, hm->uri.p);
return; return;
} }

View file

@ -59,8 +59,8 @@ get_gid_for_group(char *group)
int int
helper_drop_privileges() helper_drop_privileges()
{ {
uid_t uid = get_uid_for_user(global_config.user); uid_t uid = get_uid_for_user(global_config->user);
gid_t gid = get_gid_for_group(global_config.group); gid_t gid = get_gid_for_group(global_config->group);
LOGGER_DEBUG("drop privileges to %lu:%lu\n", uid, gid); LOGGER_DEBUG("drop privileges to %lu:%lu\n", uid, gid);

View file

@ -17,7 +17,7 @@ const char *COLOR_EMERG = COLOR_MAGENTA;
void void
logger_log(int level, const char *filename, int line, const char *func, const char *msg, ...) logger_log(int level, const char *filename, int line, const char *func, const char *msg, ...)
{ {
if(global_config.log_level < level || level == LOG_NONE ) if(global_config->log_level < level || level == LOG_NONE )
{ {
return; return;
} }
@ -76,8 +76,8 @@ logger_log(int level, const char *filename, int line, const char *func, const ch
char *buffer_timed = malloc(sizeof(char) * (strlen(timestamp_str) + strlen(buffer) + 2)); char *buffer_timed = malloc(sizeof(char) * (strlen(timestamp_str) + strlen(buffer) + 2));
sprintf(buffer_timed, "%s %s", timestamp_str, buffer); sprintf(buffer_timed, "%s %s", timestamp_str, buffer);
va_start(args, msg); va_start(args, msg);
vfprintf(global_config.log_file, buffer_timed, args); vfprintf(global_config->log_file, buffer_timed, args);
fflush(global_config.log_file); fflush(global_config->log_file);
va_end(args); va_end(args);
free(buffer); free(buffer);

View file

@ -7,6 +7,7 @@
#include <confini.h> #include <confini.h>
#include <cache.h> #include <cache.h>
#include <cli.h>
#include <router.h> #include <router.h>
#include <logger.h> #include <logger.h>
#include <config.h> #include <config.h>
@ -52,22 +53,22 @@ main(int argc, const char** argv)
signal(SIGABRT, terminate); signal(SIGABRT, terminate);
signal(SIGTERM, terminate); signal(SIGTERM, terminate);
setlogmask(LOG_UPTO(LOG_INFO)); openlog("emgauwa-core", 0, LOG_USER);
setlogmask(LOG_UPTO(LOG_DEBUG));
/******************** LOAD CONFIG ********************/ /******************** LOAD CONFIG ********************/
config_init(); config_init();
helper_parse_cli(argc, argv, &global_config); cli_parse(argc, argv, global_config);
FILE * const ini_file = fopen(global_config.file, "rb"); FILE * const ini_file = fopen(global_config->file, "rb");
if(ini_file == NULL) if(ini_file == NULL)
{ {
LOGGER_CRIT("config file '%s' was not found\n", global_config.file); LOGGER_CRIT("config file '%s' was not found\n", global_config->file);
exit(1); exit(1);
} }
if(load_ini_file(ini_file, INI_DEFAULT_FORMAT, NULL, config_load, &global_config)) if(load_ini_file(ini_file, INI_DEFAULT_FORMAT, NULL, config_load, global_config))
{ {
LOGGER_CRIT("unable to parse ini file\n"); LOGGER_CRIT("unable to parse ini file\n");
exit(1); exit(1);
@ -75,16 +76,12 @@ main(int argc, const char** argv)
fclose(ini_file); fclose(ini_file);
memset(&global_config.http_server_opts, 0, sizeof(global_config.http_server_opts)); if(global_config->log_file == NULL)
global_config.http_server_opts.document_root = global_config.content_dir;
global_config.http_server_opts.enable_directory_listing = "no";
global_config.http_server_opts.extra_headers = "Access-Control-Allow-Origin: *\r\nAccess-Control-Allow-Headers: *\r\nAccess-Control-Allow-Methods: *";
if(global_config.log_file == NULL)
{ {
global_config.log_file = stdout; global_config->log_file = stdout;
} }
openlog("emgauwa-core", 0, LOG_USER);
LOGGER_DEBUG("Loaded config from %s\n", global_config->file);
/******************** SETUP CONNECTION ********************/ /******************** SETUP CONNECTION ********************/
@ -94,20 +91,20 @@ main(int argc, const char** argv)
mg_mgr_init(&mgr, NULL); mg_mgr_init(&mgr, NULL);
char address[100]; char address[100];
sprintf(address, "tcp://0.0.0.0:%u", global_config.server_port); sprintf(address, "tcp://0.0.0.0:%u", global_config->server_port);
struct mg_connection *c_http = mg_bind(&mgr, address, handler_http); struct mg_connection *c_http = mg_bind(&mgr, address, handler_http);
if(c_http == NULL) if(c_http == NULL)
{ {
LOGGER_CRIT("failed to bind http server to port %u\n", global_config.server_port); LOGGER_CRIT("failed to bind http server to port %u\n", global_config->server_port);
exit(1); exit(1);
} }
mg_set_protocol_http_websocket(c_http); mg_set_protocol_http_websocket(c_http);
sprintf(address, "tcp://0.0.0.0:%u", global_config.mqtt_port); sprintf(address, "tcp://0.0.0.0:%u", global_config->mqtt_port);
struct mg_connection *c_mqtt = mg_bind(&mgr, address, handler_mqtt); struct mg_connection *c_mqtt = mg_bind(&mgr, address, handler_mqtt);
if(c_mqtt == NULL) if(c_mqtt == NULL)
{ {
LOGGER_CRIT("failed to bind mqtt server to port %u\n", global_config.mqtt_port); LOGGER_CRIT("failed to bind mqtt server to port %u\n", global_config->mqtt_port);
exit(1); exit(1);
} }
mg_mqtt_broker_init(&brk, NULL); mg_mqtt_broker_init(&brk, NULL);
@ -116,6 +113,11 @@ main(int argc, const char** argv)
helper_drop_privileges(); helper_drop_privileges();
memset(&global_config->http_server_opts, 0, sizeof(global_config->http_server_opts));
global_config->http_server_opts.document_root = global_config->content_dir;
global_config->http_server_opts.enable_directory_listing = "no";
global_config->http_server_opts.extra_headers = "Access-Control-Allow-Origin: *\r\nAccess-Control-Allow-Headers: *\r\nAccess-Control-Allow-Methods: *";
/******************** INIT COMPONENTS ********************/ /******************** INIT COMPONENTS ********************/

View file

@ -41,12 +41,7 @@ touch $working_dir/index.html
cp $1 $working_dir/core cp $1 $working_dir/core
echo "=== invalids start (must exit) ===" >$working_dir/core.log valgrind_emgauwa $working_dir/core -c $source_dir/emgauwa-core-testing.ini >>$working_dir/core.log 2>&1 &
$working_dir/core -c $source_dir/emgauwa-core-testing-ini >>$working_dir/core.log 2>&1
$working_dir/core -c $source_dir/emgauwa-core-testing-ini INVALID_ACTION >>$working_dir/core.log 2>&1
echo "=== valid start ===" >>$working_dir/core.log
valgrind_emgauwa $working_dir/core -c $source_dir/emgauwa-core-testing.ini start >>$working_dir/core.log 2>&1 &
core_id=$! core_id=$!