From 3f931bac28a9549bfda1a62f699e967769f11e4b Mon Sep 17 00:00:00 2001 From: Kubat <mael.martin31@gmail.com> Date: Thu, 9 Apr 2020 20:21:47 +0200 Subject: [PATCH] WIP: Changing the way config is stored. --- inc/lektor/config.h | 34 +--- inc/lektor/database.h | 4 +- inc/lektor/net.h | 2 +- meson.build | 2 +- src/config.c | 219 +++++++++++++++++++++++ src/config.cpp | 393 ------------------------------------------ src/database/config.c | 38 ++++ src/database/open.c | 36 ++-- src/main/lktadm.c | 24 ++- src/main/server.c | 14 +- src/net/listen.c | 58 +++++-- 11 files changed, 343 insertions(+), 481 deletions(-) create mode 100644 src/config.c delete mode 100644 src/config.cpp diff --git a/inc/lektor/config.h b/inc/lektor/config.h index c517b035..d253fcc8 100644 --- a/inc/lektor/config.h +++ b/inc/lektor/config.h @@ -1,7 +1,7 @@ #pragma once #include <stddef.h> - +#include <sqlite3.h> static const char *const lkt_default_config_file = "; Lektor's configuration file\n" @@ -52,48 +52,22 @@ static const char *const lkt_default_config_file = "specific_opt1 = 1\n" "specific_opt2 = a string\n"; -typedef void *lkt_config_t; - /* It is just an alias to the consecutive use of config_detect_file and config_new function, with the return an '&&' between the two returns of the two other functions. */ -int config_open(lkt_config_t *conf); +int config_open(sqlite3 *db); /* Get the path to the config file that may be red, taking into account the priority between existing files. The returned path is a path to an existing file. If no file is found, returns a non zero value. Returns 1 otherwise. */ int config_detect_file(char **conf, size_t conf_len); -/* Simply free a configuration. */ -void config_free(lkt_config_t *conf); - /* Create and read the configuration in the conf file and write it into lkt_conf. The type is opaque because it's a C++ class. Return 0 if the read operation was a success, a non zero value otherwise. */ -int config_new(const char *conf, lkt_config_t *lkt_conf); +int config_new(sqlite3 *db, const char *conf); /* Load a module by its name. Also initialize the mod pointer. No check on data type is done, it is up to the user to check if the structure passed as a `void*` is the right structure. */ -int load_module_by_name(lkt_config_t conf, const char *name, void *mod); - -/* Get the value of a parameter in the configuration. The value is stored as a - string in the ret pointer. This string will be null-terminated. If the result - is longer than the size of ret (as specified by the max_len) the result will - be truncated to max_len characters including the null termination byte. */ -int config_get(lkt_config_t conf, const char *section, const char *opt, - char *const ret, const size_t max_len); - -/* Get the value of a parameter in the configuration as an integer. If there was - an error return a non zero value. If the value was retrieved without any error - return 0. */ -int config_get_int(lkt_config_t conf, const char *section, const char *opt, int *ret); - -/* Get the value of a parameter. The `char*` will be allocated BY THIS FUNCTION, - do not malloc or calloc the `char *ret` pointer before. - Returns 0 is everything was successfull, a non zero value otherwise. */ -int config_get_alloc(lkt_config_t conf, const char *section, const char *opt, char **ret); - -/* Get the value of a parameter as a boolean. - Returns 0 is everything was successfull, a non zero value otherwise. */ -int config_get_bool(lkt_config_t conf, const char *section, const char *opt, int *ret); +int load_module_by_name(sqlite3 *db, const char *name, void *mod); diff --git a/inc/lektor/database.h b/inc/lektor/database.h index a6dbe24e..303d8499 100644 --- a/inc/lektor/database.h +++ b/inc/lektor/database.h @@ -32,7 +32,8 @@ struct lkt_queue_state { }; /* Open correctly a database for lektor. */ -bool database_open(sqlite3 **db, const char *dbpath); +bool database_new(sqlite3 **db); +bool database_open(sqlite3 *db, const char *dbpath); /* Get information on the queue and currently playing kara. */ bool database_queue_state(sqlite3 *db, struct lkt_queue_state *res); @@ -101,6 +102,7 @@ bool database_queue_prev(sqlite3 *db, char filepath[PATH_MAX]); bool database_config_set(sqlite3 *db, const char *section, const char *key, const char *value); bool database_config_get_text(sqlite3 *db, const char *section, const char *key, char *value, size_t len); bool database_config_get_int(sqlite3 *db, const char *section, const char *key, int *value); +bool database_config_exists(sqlite3 *db, const char *section, const char *key); bool database_config_queue(sqlite3 *db, const char *option, int value); bool database_config_queue_default(sqlite3 *db); diff --git a/inc/lektor/net.h b/inc/lektor/net.h index c1ce1b20..c4f3d86d 100644 --- a/inc/lektor/net.h +++ b/inc/lektor/net.h @@ -76,4 +76,4 @@ long long int *lkt_client_get_mask(struct lkt_state *srv, size_t c); bool lkt_client_auth(struct lkt_state *srv, size_t c, bool set_auth); /* The server's listen function. */ -int lkt_listen(lkt_config_t conf); +int lkt_listen(void); diff --git a/meson.build b/meson.build index 5a881e22..eeb33764 100644 --- a/meson.build +++ b/meson.build @@ -40,7 +40,7 @@ core_sources = [ 'src/mkv/bufferfd.c' , 'src/net/command.c' , 'src/net/listen.c' , 'src/net/message.c' - , 'src/config.cpp' + , 'src/config.c' , 'src/utils.c' , 'src/uri.c' , 'src/ini/ini.c' diff --git a/src/config.c b/src/config.c new file mode 100644 index 00000000..4a4771c0 --- /dev/null +++ b/src/config.c @@ -0,0 +1,219 @@ +#define _POSIX_C_SOURCE 200809L + +#include <lektor/config.h> +#include <lektor/database.h> +#include <ini/ini.h> +#include <stdlib.h> +#include <errno.h> +#include <string.h> +#include <dlfcn.h> +#include <stdio.h> +#include <pwd.h> +#include <unistd.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <limits.h> + +static inline int +load_so(const char *const mod_path, const char *const mod_init, void *mod) +{ + /* An init function takes two arguments: the module pointer and a void* + which is the handler for the .so file. It the role of the module to + store the handle pointer. + Uppon successfull completion, the function shall return 0, and return + a non zero value if something bad happened. */ + int (*module_set_function)(void *const, void *const); + char *error; + void *handle = dlopen(mod_path, RTLD_NOW); + + if (NULL == handle) { + fprintf(stderr, " ! load_so: libdl error in dlopen: %s\n", dlerror()); + return 1; + } + + dlerror(); + *(void **) (&module_set_function) = dlsym(handle, mod_init); + + if ((error = dlerror()) != NULL) { + fprintf(stderr, " ! load_so: libdl error in dlsym: %s\n", error); + return 1; + } + + return ! module_set_function(mod, handle); +} + +inline int +load_module_by_name(sqlite3 *db, const char *name, void *mod) +{ + char mod_path[PATH_MAX], mod_load[INI_MAX_LINE]; + + if (!database_config_get_text(db, name, "path", mod_path, PATH_MAX) || + !database_config_get_text(db, name, "load_function", mod_load, INI_MAX_LINE)) { + fprintf(stderr, " ! load_module_by_name: Module named %s is incomplete or is not " + "defined in config file", name); + return 1; + } + + return load_so(mod_path, mod_load, mod); +} + +inline static int +validate_conf(sqlite3 *db) +{ +#define CHK_OPTION(section, name) \ + if (!database_config_exists(db, section, name)) { \ + fprintf(stderr, " ! validate_conf: Missing option " name " in section " section "\n"); \ + return 1; \ + } + + CHK_OPTION("externals", "mkvpropedit"); + CHK_OPTION("externals", "sqlite3"); + + CHK_OPTION("server", "host"); + CHK_OPTION("server", "port"); + CHK_OPTION("server", "max_clients"); + + CHK_OPTION("player", "module"); + CHK_OPTION("player", "autoclear"); + CHK_OPTION("player", "def_random"); + CHK_OPTION("player", "def_consume"); + CHK_OPTION("player", "def_single"); + CHK_OPTION("player", "def_repeat"); + + CHK_OPTION("database", "kara_dir"); + CHK_OPTION("database", "db_path"); + + return 0; +} + +static int +#if INI_HANDLER_LINENO +handler(void *user, const char *section, const char *name, const char *value, int lineno) +{ + (void) lineno; +#else +handler(void *user, const char *section, const char *name, const char *value) +{ +#endif + if (!section || !name || !value) { + fprintf(stderr, " . handler: I can't complete the database with incomplete lines\n"); + return 1; + } + + if (database_config_set(user, section, name, value)) { + fprintf(stderr, " . handler: Failed to update the database\n"); + return 1; + } + + return 0; +} + +int +config_detect_file(char **conf, size_t conf_len) +{ + bool is_malloc = false; + struct passwd *pw = getpwuid(getuid()); + char *home; + + if (conf == NULL) + return 1; + + if (*conf == NULL) { + *conf = (char *) calloc(conf_len, sizeof(char)); + + if (!*conf) + return ENOMEM; + } + + memset(*conf, 0, conf_len * sizeof(char)); + + /* Try the current working dir config file. */ + if (getcwd(*conf, conf_len - 1) != NULL) { + strncat(*conf, "/lektor.ini", conf_len - 1); + fprintf(stderr, " . config_detect_file: trying %s\n", *conf); + if (!access(*conf, R_OK)) + goto found; + } + + /* Try the config file from the config directory. */ + home = getenv("XDG_CONFIG_HOME"); + if (!home || (strlen(home) >= conf_len)) + home = getenv("HOME"); + if (!home || (strlen(home) >= conf_len)) + home = pw->pw_dir; + if (!home || (strlen(home) >= conf_len)) + goto no_config_directory; + memcpy(*conf, home, (strlen(home) + 1) * sizeof(char)); + strncat(*conf, "/.config/lektor/lektor.ini", conf_len - 1); + fprintf(stderr, " . config_detect_file: trying %s\n", *conf); + if (!access(*conf, R_OK | F_OK)) + goto found; + +no_config_directory: + /* Try the '/opt/lektor' file. */ + memcpy(*conf, "/opt/lektor/lektor.ini", sizeof("/opt/lektor/lektor.ini")); + fprintf(stderr, " . config_detect_file: trying %s\n", *conf); + if (!access(*conf, R_OK)) + goto found; + + /* Try the '/usr/local/etc/lektor.ini' file. */ + memcpy(*conf, "/usr/local/etc/lektor.ini", sizeof("/opt/lektor/lektor.ini")); + fprintf(stderr, " . config_detect_file: trying %s\n", *conf); + if (!access(*conf, R_OK)) + goto found; + + /* Try the '/etc/lektor.ini' file. */ + memcpy(*conf, "/etc/lektor.ini", sizeof("/etc/lektor.ini")); + fprintf(stderr, " . config_detect_file: trying %s\n", *conf); + if (!access(*conf, R_OK)) + goto found; + + /* Error */ + fprintf(stderr, "config_detect_file: an error occured with file %s: %s", + *conf, strerror(errno)); + if (is_malloc) + free(*conf); + return 1; +found: + fprintf(stderr, " . config_detect_file: using file %s\n", *conf); + return 0; +} + +int +config_new(sqlite3 *db, const char *conf) +{ + if (ini_parse(conf, handler, db)) { + fprintf(stderr, " . config_new: Failed to parse file %s\n", conf); + return 1; + } + + if (validate_conf(db)) { + fprintf(stderr, " . config_new: Configuration file %s is incomplete\n", conf); + return 1; + } + + return 0; +} + +int +config_open(sqlite3 *db) +{ + char *conf_file = NULL; + int ret = 1; + + if (config_detect_file(&conf_file, PATH_MAX)) { + fprintf(stderr, " ! config_open: error while searching for a config file\n"); + goto error; + } + + if (config_new(db, conf_file)) { + fprintf(stderr, " ! config_open: failed to read configuration file\n"); + goto error; + } + + ret = 0; +error: + if (conf_file) + free(conf_file); + return ret; +} diff --git a/src/config.cpp b/src/config.cpp deleted file mode 100644 index e5dfb425..00000000 --- a/src/config.cpp +++ /dev/null @@ -1,393 +0,0 @@ -#define _POSIX_C_SOURCE 200809L - -/* Perform includes. */ - -extern "C" -{ -#include <lektor/config.h> -#include <dlfcn.h> -#include <stdio.h> -#include <pwd.h> -#include <unistd.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <errno.h> -#include <stdlib.h> -#include <limits.h> -} - -#include <ini/ini.hpp> -#include <string> -#include <cstring> - -/* Function to load a .so as a lektor's module. */ -extern "C" inline int -load_so(const char *const mod_path, const char *const mod_init, void *mod) -{ - /* An init function takes two arguments: the module pointer and a void* - which is the handler for the .so file. It the role of the module to - store the handle pointer. - Uppon successfull completion, the function shall return 0, and return - a non zero value if something bad happened. */ - int (*module_set_function)(void *const, void *const); - char *error; - void *handle = dlopen(mod_path, RTLD_NOW); - - if (NULL == handle) { - fprintf(stderr, " ! load_so: libdl error in dlopen: %s\n", dlerror()); - return 1; - } - - dlerror(); - *(void **) (&module_set_function) = dlsym(handle, mod_init); - - if ((error = dlerror()) != NULL) { - fprintf(stderr, " ! load_so: libdl error in dlsym: %s\n", error); - return 1; - } - - return ! module_set_function(mod, handle); -} - -/* Real functions here, C++ functions. */ - -inline static void -__config_free(lkt_config_t *conf) -{ - delete reinterpret_cast<INIReader *>(*conf); - *conf = nullptr; -} - -inline static int -validate_conf(const INIReader *const ini) -{ - /* Check for mendatory sections. */ -#define CHK_SECTION(name) \ - if (!ini->HasSection(name)) \ - { \ - fprintf(stderr, " ! validate_conf: missing section %s\n", name); \ - return 1; \ - } - - CHK_SECTION("externals"); - CHK_SECTION("server"); - CHK_SECTION("player"); - CHK_SECTION("database"); - - /* Check for mendatory options. */ - -#define CHK_OPTION(section, name) \ - if (!ini->HasValue(section, name)) \ - { \ - fprintf(stderr, " ! validate_conf: missing option %s in section %s\n", name, section); \ - return 1; \ - } - - CHK_OPTION("externals", "mkvpropedit"); - CHK_OPTION("externals", "sqlite3"); - - CHK_OPTION("server", "host"); - CHK_OPTION("server", "port"); - CHK_OPTION("server", "max_clients"); - - CHK_OPTION("player", "module"); - CHK_OPTION("player", "autoclear"); - CHK_OPTION("player", "def_random"); - CHK_OPTION("player", "def_consume"); - CHK_OPTION("player", "def_single"); - CHK_OPTION("player", "def_repeat"); - - CHK_OPTION("database", "kara_dir"); - CHK_OPTION("database", "db_path"); - - /* Everything is OK. */ - - return 0; -} - -inline static int -__config_new(const char *conf, lkt_config_t *lkt_conf) -{ - INIReader *ini = nullptr; - int status; - - try { - ini = new INIReader(std::string(conf)); - *lkt_conf = ini; - } catch (...) { - return 1; - } - - /* Is parsing OK? */ - - status = ini->ParseError(); - - if (status == -1) { - fprintf(stderr, " ! config_new: could not read file %s\n", conf); - return 1; - } - - if (status > 0) { - fprintf(stderr, " ! config_new: error on line %d in file %s\n", status, conf); - return 1; - } - - /* We need some basic options to be happy here. */ - - if (validate_conf(ini)) { - fprintf(stderr, " ! config_new: some basic options are missing in file %s\n", conf); - return 2; - } - - /* Now everything is OK. */ - - return 0; -} - -inline static int -__load_module_by_name(lkt_config_t const conf, const char *name, void *mod) -{ - INIReader *ini = reinterpret_cast<INIReader *>(conf); - - if (!ini->HasSection(name)) { - fprintf(stderr, " ! load_module_by_name: No module named %s in the conf file\n", name); - return 1; - } - - std::string mod_path = ini->GetString(name, "path", ""); - std::string mod_load = ini->GetString(name, "load_function", ""); - - if (mod_path.empty() || mod_load.empty()) { - fprintf(stderr, " ! load_module_by_name: " - "options 'path' and 'load_function' may be absent or empty " - "in the section %s\n", name); - return 2; - } - - return load_so(mod_path.c_str(), mod_load.c_str(), mod); -} - -static int -__config_get(lkt_config_t conf, const char *section, const char *opt, - char *const ret, const size_t max_len) -{ - INIReader *ini = reinterpret_cast<INIReader *>(conf); - - if (!ini->HasValue(section, opt)) - return 1; - - std::string value = ini->GetString(section, opt, ""); - - if (value.empty()) - return 2; - - size_t max_idx = std::min(value.size() + 1, max_len); - ret[max_idx] = 0; - memcpy(ret, value.c_str(), (max_idx - 1) * sizeof(char)); - - return 0; -} - -static int -__config_get(lkt_config_t conf, const char *section, const char *opt, - int *const ret) -{ - INIReader *ini = reinterpret_cast<INIReader *>(conf); - - if (!ini->HasValue(section, opt)) - return 1; - - std::string value = ini->GetString(section, opt, ""); - - if (value.empty()) - return 2; - - try { - *ret = std::stoi(value, /* start index */ 0, /* autotedect the base */ 0); - } catch (...) { - return 3; - } - - return 0; -} - -static int -__config_get(lkt_config_t conf, const char *section, const char *opt, - bool *const ret) -{ - INIReader *ini = reinterpret_cast<INIReader *>(conf); - - if (!ini->HasValue(section, opt)) - return 1; - - *ret = ini->GetBoolean(section, opt, false); - return 0; -} - -static int -__config_get(lkt_config_t conf, const char *section, const char *opt, char **ret) -{ - INIReader *ini = reinterpret_cast<INIReader *>(conf); - - if (!ini->HasValue(section, opt)) - return 1; - - std::string value = ini->GetString(section, opt, ""); - - if (value.empty()) - return 2; - - size_t max_idx = value.size(); - - /* Yes, use calloc here. */ - *ret = reinterpret_cast<char *>(calloc(max_idx + 1, sizeof(char))); - (*ret)[max_idx] = 0; - memcpy(*ret, value.c_str(), max_idx * sizeof(char)); - - return 0; -} - -/* Bindings to C functions. */ - -extern "C" -{ - void - config_free(lkt_config_t *conf) - { - __config_free(conf); - } - - int - config_new(const char *conf, lkt_config_t *lkt_conf) - { - return __config_new(conf, lkt_conf); - } - - int - load_module_by_name(lkt_config_t conf, const char *name, void *mod) - { - return __load_module_by_name(conf, name, mod); - } - - int - config_get(lkt_config_t conf, const char *section, const char *opt, - char *const ret, const size_t max_len) - { - return __config_get(conf, section, opt, ret, max_len); - } - - int - config_get_int(lkt_config_t conf, const char *section, const char *opt, int *ret) - { - return __config_get(conf, section, opt, ret); - } - - int - config_get_alloc(lkt_config_t conf, const char *section, const char *opt, char **ret) - { - return __config_get(conf, section, opt, ret); - } - - int - config_get_bool(lkt_config_t conf, const char *section, const char *opt, int *ret) - { - bool ret__ = false; - int status = __config_get(conf, section, opt, &ret__); - *ret = ret__; - return status; - } - - int - config_detect_file(char **conf, size_t conf_len) - { - bool is_malloc = false; - struct passwd *pw = getpwuid(getuid()); - char *home; - - if (conf == NULL) - return 1; - - if (*conf == NULL) { - *conf = (char *) calloc(conf_len, sizeof(char)); - - if (!*conf) - return ENOMEM; - } - - memset(*conf, 0, conf_len * sizeof(char)); - - /* Try the current working dir config file. */ - if (getcwd(*conf, conf_len - 1) != NULL) { - strncat(*conf, "/lektor.ini", conf_len - 1); - fprintf(stderr, " . config_detect_file: trying %s\n", *conf); - if (!access(*conf, R_OK)) - goto found; - } - - /* Try the config file from the config directory. */ - home = getenv("XDG_CONFIG_HOME"); - if (!home || (strlen(home) >= conf_len)) - home = getenv("HOME"); - if (!home || (strlen(home) >= conf_len)) - home = pw->pw_dir; - if (!home || (strlen(home) >= conf_len)) - goto no_config_directory; - memcpy(*conf, home, (strlen(home) + 1) * sizeof(char)); - strncat(*conf, "/.config/lektor/lektor.ini", conf_len - 1); - fprintf(stderr, " . config_detect_file: trying %s\n", *conf); - if (!access(*conf, R_OK | F_OK)) - goto found; - -no_config_directory: - /* Try the '/opt/lektor' file. */ - memcpy(*conf, "/opt/lektor/lektor.ini", sizeof("/opt/lektor/lektor.ini")); - fprintf(stderr, " . config_detect_file: trying %s\n", *conf); - if (!access(*conf, R_OK)) - goto found; - - /* Try the '/usr/local/etc/lektor.ini' file. */ - memcpy(*conf, "/usr/local/etc/lektor.ini", sizeof("/opt/lektor/lektor.ini")); - fprintf(stderr, " . config_detect_file: trying %s\n", *conf); - if (!access(*conf, R_OK)) - goto found; - - /* Try the '/etc/lektor.ini' file. */ - memcpy(*conf, "/etc/lektor.ini", sizeof("/etc/lektor.ini")); - fprintf(stderr, " . config_detect_file: trying %s\n", *conf); - if (!access(*conf, R_OK)) - goto found; - - /* Error */ - fprintf(stderr, "config_detect_file: an error occured with file %s: %s", - *conf, strerror(errno)); - if (is_malloc) - free(*conf); - return 1; -found: - fprintf(stderr, " . config_detect_file: using file %s\n", *conf); - return 0; - } - - int - config_open(lkt_config_t *conf) - { - char *conf_file = NULL; - int ret = 1; - - if (config_detect_file(&conf_file, PATH_MAX)) { - fprintf(stderr, " ! config_open: error while searching for a config file\n"); - goto error; - } - - if (config_new(conf_file, conf)) { - fprintf(stderr, " ! config_open: failed to read configuration file\n"); - goto error; - } - - ret = 0; -error: - if (conf_file) - free(conf_file); - return ret; - } -} diff --git a/src/database/config.c b/src/database/config.c index 77819dea..362ebf6b 100644 --- a/src/database/config.c +++ b/src/database/config.c @@ -86,6 +86,44 @@ error: return ret; } +bool +database_config_exists(sqlite3 *db, const char *section, const char *key) +{ + static const char *SQL_STMT = + "SELECT COUNT(value)" + " FROM config" + " WHERE section = ? AND key = ?;\n"; + sqlite3_stmt *stmt = 0; + bool ret = false; + int code; + + if (sqlite3_prepare_v2(db, SQL_STMT, -1, &stmt, 0) != SQLITE_OK) { + fprintf(stderr, " ! database_config_exists: Failed to prepare statement: %s\n", + sqlite3_errmsg(db)); + goto error; + } + + if (sqlite3_bind_text(stmt, 1, section, -1, 0) != SQLITE_OK || + sqlite3_bind_text(stmt, 2, key, -1, 0) != SQLITE_OK) { + fprintf(stderr, " ! database_config_exists: Failed to bind: %s\n", + sqlite3_errmsg(db)); + goto error; + } + + code = sqlite3_step(stmt); + + if (code != SQLITE_ROW) { + fprintf(stderr, " ! database_config_exists: Failed to insert or replace: %s\n", + sqlite3_errmsg(db)); + goto error; + } + + ret = (0 < sqlite3_column_int(stmt, 1)); +error: + sqlite3_finalize(stmt); + return ret; +} + bool database_config_get_int(sqlite3 *db, const char *section, const char *key, int *value) { diff --git a/src/database/open.c b/src/database/open.c index 915da6a6..b493bf26 100644 --- a/src/database/open.c +++ b/src/database/open.c @@ -32,7 +32,7 @@ static const char *const SQL_MEM_SCHEM = "CREATE TABLE IF NOT EXISTS config" " ( section TEXT NOT NULL" " , key TEXT NOT NULL" - " , value TEXT NOT NULL" + " , value TEXT" " , PRIMARY KEY (section, key)" " ) WITHOUT ROWID;\n"; @@ -48,25 +48,20 @@ is_sql_str_invalid(const char *str) } bool -database_open(sqlite3 **db, const char *dbpath) +database_new(sqlite3 **db) { - if (is_sql_str_invalid(dbpath)) { - fprintf(stderr, " ! database_open: The database path %s is invalid\n", dbpath); - return false; - } - if (SQLITE_OK != sqlite3_enable_shared_cache(1)) { - fprintf(stderr, " ! database_open: Failed to enable shared cache\n"); + fprintf(stderr, " ! database_new: Failed to enable shared cache\n"); return false; } if (sqlite3_soft_heap_limit64(HEAP_LIMIT_SOFT) < 0) { - fprintf(stderr, " ! database_open: Failed to set soft heap limit to %u\n", HEAP_LIMIT_SOFT); + fprintf(stderr, " ! database_new: Failed to set soft heap limit to %u\n", HEAP_LIMIT_SOFT); return false; } if (sqlite3_hard_heap_limit64(HEAP_LIMIT_HARD) < 0) { - fprintf(stderr, " ! database_open: Failed to set soft heap limit to %u\n", HEAP_LIMIT_HARD); + fprintf(stderr, " ! database_new: Failed to set soft heap limit to %u\n", HEAP_LIMIT_HARD); return false; } @@ -86,14 +81,28 @@ database_open(sqlite3 **db, const char *dbpath) goto err_not_init; } + return true; +err_not_init: + *db = NULL; + return false; +} + +bool +database_open(sqlite3 *db, const char *dbpath) +{ + if (is_sql_str_invalid(dbpath)) { + fprintf(stderr, " ! database_open: The database path %s is invalid\n", dbpath); + return false; + } + static const char SQL_ATTACH_TEMPLATE[] = "ATTACH '%s' AS disk;"; size_t len = strlen(dbpath) + (sizeof(SQL_ATTACH_TEMPLATE) / sizeof(char)); char *SQL_ATTACH = (char *) calloc(len, sizeof(char)); snprintf(SQL_ATTACH, len - 1, SQL_ATTACH_TEMPLATE, dbpath); - if (SQLITE_OK != sqlite3_exec(*db, SQL_ATTACH, 0, 0, 0)) { + if (SQLITE_OK != sqlite3_exec(db, SQL_ATTACH, 0, 0, 0)) { fprintf(stderr, " ! database_open: Failed to attach disk database %s: %s\n", - dbpath, sqlite3_errmsg(*db)); + dbpath, sqlite3_errmsg(db)); goto err_no_attach; } @@ -101,8 +110,5 @@ database_open(sqlite3 **db, const char *dbpath) err_no_attach: free(SQL_ATTACH); - sqlite3_close(*db); -err_not_init: - *db = NULL; return false; } diff --git a/src/main/lktadm.c b/src/main/lktadm.c index caddcd63..cd08470c 100644 --- a/src/main/lktadm.c +++ b/src/main/lktadm.c @@ -31,8 +31,7 @@ main(int argc, char *argv[]) int i, num; sqlite3 *db; bool ret = true; - lkt_config_t conf; - char kara_dir[PATH_MAX], *db_path, *mkvpropedit, buf[100]; + char kara_dir[PATH_MAX], *db_path, mkvpropedit[PATH_MAX], buf[100]; struct kara_metadata data; struct lkt_repo repo; @@ -41,13 +40,18 @@ main(int argc, char *argv[]) /* Read the config file. */ - if (config_open(&conf)) { + if (!database_new(&db)) { + fprintf(stderr, " ! Failed to initialize memory database\n"); + return 1; + } + + if (config_open(db)) { fprintf(stderr, " ! could not load configuration\n"); return 1; } /* In any case, we won't free the mkvpropedit, this is not a daemon. */ - if (config_get_alloc(conf, "externals", "mkvpropedit", &mkvpropedit)) { + if (database_config_get_text(db, "externals", "mkvpropedit", mkvpropedit, PATH_MAX)) { fprintf(stderr, " ! could not get the 'mkvpropedit property from the externals section\n'"); return 1; } @@ -55,7 +59,7 @@ main(int argc, char *argv[]) /* Arguments handle. */ if (strcmp(argv[1], "--init") == 0) { - if (config_get(conf, "database", "kara_dir", kara_dir, PATH_MAX)) { + if (database_config_get_text(db, "database", "kara_dir", kara_dir, PATH_MAX)) { fprintf(stderr, " ! failed to get the kara directory\n"); return 10; } @@ -66,17 +70,21 @@ main(int argc, char *argv[]) else if (strcmp(argv[1], "--populate-all") == 0) { db_path = (char *) calloc(PATH_MAX, sizeof(char)); - if (config_get(conf, "database", "db_path", db_path, PATH_MAX)) { + if (database_config_get_text(db, "database", "db_path", db_path, PATH_MAX)) { fprintf(stderr, " ! Failed to get database path\n"); goto end_populate; } - if (config_get(conf, "database", "kara_dir", kara_dir, PATH_MAX)) { + if (database_config_get_text(db, "database", "kara_dir", kara_dir, PATH_MAX)) { fprintf(stderr, " ! Failed to get kara directory\n"); goto end_populate; } - sqlite3_open(db_path, &db); + if (!database_open(db, db_path)) { + fprintf(stderr, " ! lkt_listen: Failed to open database\n"); + return 1; + } + database_update(db, kara_dir); sqlite3_close(db); diff --git a/src/main/server.c b/src/main/server.c index 99115376..ba4eea5e 100644 --- a/src/main/server.c +++ b/src/main/server.c @@ -37,8 +37,6 @@ main(int argc, char *argv[]) { /* Variable initialisation */ struct passwd *pw = getpwuid(getuid()); - char *conf_file = NULL; - lkt_config_t conf; /* Argument handleing */ if (argc <= 1) @@ -59,15 +57,5 @@ normal_launch: fprintf(stderr, " * Lektor launched by user %s (shell: %s, home: %s)\n", pw->pw_name, pw->pw_shell, pw->pw_dir); - if (config_detect_file(&conf_file, PATH_MAX)) { - fprintf(stderr, " ! error while searching for a config file\n"); - return 1; - } - - if (config_new(conf_file, &conf)) { - fprintf(stderr, " ! failed to read configuration file\n"); - return 1; - } - - return lkt_listen(conf); + return lkt_listen(); } diff --git a/src/net/listen.c b/src/net/listen.c index f70f6a4a..71072802 100644 --- a/src/net/listen.c +++ b/src/net/listen.c @@ -4,6 +4,7 @@ #include <lektor/database.h> #include <lektor/repo.h> #include <lektor/net.h> +#include <ini/ini.h> #include <sqlite3.h> @@ -705,45 +706,69 @@ get_out: } int -lkt_listen(lkt_config_t conf) +lkt_listen(void) { struct lkt_state srv; struct lkt_repo repo; int autoclear; + char *db_path = (char *) calloc(PATH_MAX, sizeof(char)); + char *kara_dir = (char *) calloc(PATH_MAX, sizeof(char)); + char *host = (char *) calloc(HOST_NAME_MAX, sizeof(char)); + char port[7]; /* Maximal port number is 65535, +2 for '\n' and '\0' */ + char player_mod[INI_MAX_LINE]; + char *conf_file; memset(&srv, 0, sizeof(struct lkt_state)); - if (config_get_bool(conf, "player", "autoclear", &autoclear)) { - fprintf(stderr, " ! Failed to get queue autoclear property\n"); + /* Initialize the system. */ + + if (!database_new(&srv.db)) { + fprintf(stderr, " ! lkt_listen: Failed to initialize memory database\n"); return 1; } - char *db_path = (char *) calloc(PATH_MAX, sizeof(char)); - char *kara_dir = (char *) calloc(PATH_MAX, sizeof(char)); - char *host = (char *) calloc(HOST_NAME_MAX, sizeof(char)); - char port[5]; /* Maximal port number is 65535. */ - char *player_mod; + if (config_detect_file(&conf_file, PATH_MAX)) { + fprintf(stderr, " ! error while searching for a config file\n"); + return 1; + } + + if (config_new(srv.db, conf_file)) { + fprintf(stderr, " ! failed to read configuration file\n"); + return 1; + } - if (config_get(conf, "database", "db_path", db_path, PATH_MAX)) { + if (!database_open(srv.db, db_path)) { + fprintf(stderr, " ! lkt_listen: Failed to open database\n"); + return 1; + } + + /* Read the configuration. */ + + if (database_config_get_int(srv.db, "player", "autoclear", &autoclear)) { + fprintf(stderr, " ! Failed to get queue autoclear property\n"); + return 1; + } + + if (database_config_get_text(srv.db, "database", "db_path", db_path, PATH_MAX)) { fprintf(stderr, " ! lkt_listen: Failed to get database path\n"); goto end_free_strings; } - if (config_get(conf, "database", "kara_dir", kara_dir, PATH_MAX)) { + if (database_config_get_text(srv.db, "database", "kara_dir", kara_dir, PATH_MAX)) { fprintf(stderr, " ! lkt_listen: Failed to get kara directory\n"); goto end_free_strings; } - if (config_get(conf, "server", "host", host, HOST_NAME_MAX)) { + if (database_config_get_text(srv.db, "server", "host", host, HOST_NAME_MAX)) { fprintf(stderr, " ! lkt_listen: Failed to get the host\n"); goto end_free_strings; } - if (config_get(conf, "server", "port", port, 5)) { + if (database_config_get_text(srv.db, "server", "port", port, 5)) { fprintf(stderr, " ! lkt_listen: Failed to get the port\n"); goto end_free_strings; } - if (config_get_alloc(conf, "player", "module", &player_mod)) { + if (database_config_get_text(srv.db, "player", "module", player_mod, INI_MAX_LINE)) { fprintf(stderr, " ! lkt_listen: Failed to get the module for the player\n"); goto end_free_strings; } @@ -751,11 +776,6 @@ lkt_listen(lkt_config_t conf) if (kara_dir[strlen(kara_dir) - 1] != '/') strncat(kara_dir, "/", PATH_MAX - 1); - if (!database_open(&srv.db, db_path)) { - fprintf(stderr, " ! lkt_listen: Failed to open database\n"); - goto end_free_strings; - } - srv.kara_prefix = kara_dir; database_config_queue_default(srv.db); @@ -774,7 +794,7 @@ lkt_listen(lkt_config_t conf) if (autoclear) database_queue_clear(srv.db); - if (!load_module_by_name(conf, player_mod, &srv.win)) + if (!load_module_by_name(srv.db, player_mod, &srv.win)) return -2; if (!srv.win.new(&srv.win)) -- GitLab