Override config from conf.d

This commit is contained in:
Johannes Marbach
2023-03-12 20:24:28 +00:00
parent 028b1b7b2f
commit a5c69b0d0c
6 changed files with 180 additions and 64 deletions

View File

@@ -10,6 +10,7 @@ Nothing at the moment
- feat!: Handle input device connection/disconnection at runtime (#38)
- feat: Update lv_drivers to git master (2023-03-11)
- feat: Update lvgl to v8.3 (2023-03-08)
- feat!: Deprecate -c CLI option and add support for reading from /etc/unl0kr.conf.d/
## 0.3.0 (2022-11-13)

View File

@@ -39,20 +39,23 @@ A man page is planned to be added with #6. For the time being, you can get an ov
$ unl0kr --help
Usage: unl0kr [OPTION]
Unl0kr values the CRYPTTAB_TRIED variable. Upon completion, the entered
password is printed to STDOUT. All other output happens on STDERR.
Mandatory arguments to long options are mandatory for short options too.
-c, --config=PATH Locaton of the main config file. Defaults to
/etc/unl0kr.conf.
-C, --config-override Location of the config override file. Values in
this file override values for the same keys in the
main config file. If specified multiple times, the
values from consecutive files will be merged in
order.
-g, --geometry=NxM Force a display size of N horizontal times M
vertical pixels
-d --dpi=N Overrides the DPI
-h, --help Print this message and exit
-v, --verbose Enable more detailed logging output on STDERR
-V, --version Print the unl0kr version and exit
-C, --config-override Path to a config override file. Can be supplied
multiple times. Config files are merged in the
following order:
* /etc/unl0kr.conf
* /etc/unl0kr.conf.d/* (alphabetically)
* Override files (in supplied order)
-g, --geometry=NxM[@X,Y] Force a display size of N horizontal times M
vertical pixels, offset horizontally by X
pixels and vertically by Y pixels
-d --dpi=N Override the display's DPI value
-h, --help Print this message and exit
-v, --verbose Enable more detailed logging output on STDERR
-V, --version Print the unl0kr version and exit
```
For an example configuration file, see [unl0kr.conf].

View File

@@ -50,14 +50,8 @@ static void print_usage();
*/
static void init_opts(ul_cli_opts *opts) {
opts->num_config_files = 1;
opts->config_files = malloc(sizeof(char *));
if (!opts->config_files) {
ul_log(UL_LOG_LEVEL_ERROR, "Could not allocate memory for config file paths");
exit(EXIT_FAILURE);
}
opts->config_files[0] = "/etc/unl0kr.conf";
opts->num_config_files = 0;
opts->config_files = NULL;
opts->hor_res = -1;
opts->ver_res = -1;
@@ -75,13 +69,12 @@ static void print_usage() {
"password is printed to STDOUT. All other output happens on STDERR.\n"
"\n"
"Mandatory arguments to long options are mandatory for short options too.\n"
" -c, --config=PATH Locaton of the main config file. Defaults to\n"
" /etc/unl0kr.conf.\n"
" -C, --config-override Location of the config override file. Values in\n"
" this file override values for the same keys in\n"
" the main config file. If specified multiple\n"
" times, the values from consecutive files will be\n"
" merged in order.\n"
" -C, --config-override Path to a config override file. Can be supplied\n"
" multiple times. Config files are merged in the\n"
" following order:\n"
" * /etc/unl0kr.conf\n"
" * /etc/unl0kr.conf.d/* (alphabetically)\n"
" * Override files (in supplied order)\n"
" -g, --geometry=NxM[@X,Y] Force a display size of N horizontal times M\n"
" vertical pixels, offset horizontally by X\n"
" pixels and vertically by Y pixels\n"
@@ -101,7 +94,6 @@ void ul_cli_parse_opts(int argc, char *argv[], ul_cli_opts *opts) {
init_opts(opts);
struct option long_opts[] = {
{ "config", required_argument, NULL, 'c' },
{ "config-override", required_argument, NULL, 'C' },
{ "geometry", required_argument, NULL, 'g' },
{ "dpi", required_argument, NULL, 'd' },
@@ -115,9 +107,6 @@ void ul_cli_parse_opts(int argc, char *argv[], ul_cli_opts *opts) {
while ((opt = getopt_long(argc, argv, "c:C:g:d:hvV", long_opts, &index)) != -1) {
switch (opt) {
case 'c':
opts->config_files[0] = optarg;
break;
case 'C':
opts->config_files = realloc(opts->config_files, (opts->num_config_files + 1) * sizeof(char *));
if (!opts->config_files) {

151
config.c
View File

@@ -24,6 +24,7 @@
#include "lvgl/lvgl.h"
#include <dirent.h>
#include <ini.h>
#include <stdlib.h>
@@ -35,19 +36,31 @@
*/
/**
* Initialise a config options struct with default values.
* Compares two strings from opaque types.
*
* @param opts pointer to the options struct
* @param a first string as void pointer
* @param b second string as void pointer
* @return a positive integer if a > b, a negative integer if a < b and 0 otherwise
*/
static void init_opts(ul_config_opts *opts);
static int compare_strings(const void* a, const void* b);
/**
* Parse options from a configuration file.
* Checks whether a string ends with a suffix
*
* @param path path to configuration file
* @param opts pointer for writing the parsed options into
* @param string string to check
* @param suffix suffix to compare to
* @return true if the suffix matches at the end of the string, false otherwise
*/
static void parse_file(const char *path, ul_config_opts *opts);
static bool string_ends_with(const char *string, const char *suffix);
/**
* Non-recursively searches a directory for configuration files.
*
* @param path folder to search in
* @param found pointer to write found configuration file names into (to be freed by the caller)
* @param num_found pointer to write number of found files into
*/
static void find_files(const char *path, char ***found, int *num_found);
/**
* Handle parsing events from INIH.
@@ -74,26 +87,71 @@ static bool parse_bool(const char *value, bool *result);
* Static functions
*/
static void init_opts(ul_config_opts *opts) {
opts->general.animations = false;
opts->general.backend = ul_backends_backends[0] == NULL ? UL_BACKENDS_BACKEND_NONE : 0;
opts->general.timeout = 0;
opts->keyboard.autohide = true;
opts->keyboard.layout_id = SQ2LV_LAYOUT_US;
opts->keyboard.popovers = true;
opts->textarea.obscured = true;
opts->textarea.bullet = LV_SYMBOL_BULLET;
opts->theme.default_id = UL_THEMES_THEME_BREEZY_DARK;
opts->theme.alternate_id = UL_THEMES_THEME_BREEZY_LIGHT;
opts->input.keyboard = true;
opts->input.pointer = true;
opts->input.touchscreen = true;
static int compare_strings(const void* a, const void* b) {
return strcmp(*(const char**)a, *(const char**)b);
}
static void parse_file(const char *path, ul_config_opts *opts) {
if (ini_parse(path, parsing_handler, opts) != 0) {
ul_log(UL_LOG_LEVEL_ERROR, "Ignoring invalid config file %s", path);
static bool string_ends_with(const char *string, const char *suffix) {
if (!string || !suffix || strlen(suffix) > strlen(string)) {
return false;
}
return strncmp(string + strlen(string) - strlen(suffix), suffix, strlen(suffix)) == 0;
}
static void find_files(const char *path, char ***found, int *num_found) {
/* Initialise output variables */
*found = NULL;
*num_found = 0;
/* Count length of directory path */
const int path_length = strlen(path);
/* Open directory */
DIR *d = opendir(path);
if (!d) {
ul_log(UL_LOG_LEVEL_WARNING, "Could not read contents of folder %s", path);
return;
}
/* Loop over directory contents */
struct dirent *dir;
while ((dir = readdir(d)) != NULL) {
/* Ignore anything except for .conf files */
if (dir->d_type != DT_REG || !string_ends_with(dir->d_name, ".conf")) {
continue;
}
/* Grow output array */
char **tmp = realloc(*found, (*num_found + 1) * sizeof(char *));
if (!tmp) {
ul_log(UL_LOG_LEVEL_ERROR, "Could not reallocate memory for configuration file paths");
break;
}
*found = tmp;
/* Extract file name and length */
char *name = dir->d_name;
int name_length = strlen(name);
/* Allocate memory for full path */
char *found_path = malloc(path_length + name_length + 2); /* +1 for path separator and null terminator, respectively */
if (!found_path) {
ul_log(UL_LOG_LEVEL_ERROR, "Could not allocate memory for configuration file path");
break;
}
/* Build full path */
memcpy(found_path, path, path_length);
found_path[path_length] = '/';
memcpy(found_path + path_length + 1, dir->d_name, name_length + 1); /* +1 for path separator and null terminator, respectively */
/* Store file path */
(*found)[*num_found] = found_path;
*num_found += 1;
}
/* Close directory */
closedir(d);
}
static int parsing_handler(void* user_data, const char* section, const char* key, const char* value) {
@@ -196,9 +254,48 @@ static bool parse_bool(const char *value, bool *result) {
* Public functions
*/
void ul_config_parse(const char **files, int num_files, ul_config_opts *opts) {
init_opts(opts);
void ul_config_init_opts(ul_config_opts *opts) {
opts->general.animations = false;
opts->general.backend = ul_backends_backends[0] == NULL ? UL_BACKENDS_BACKEND_NONE : 0;
opts->general.timeout = 0;
opts->keyboard.autohide = true;
opts->keyboard.layout_id = SQ2LV_LAYOUT_US;
opts->keyboard.popovers = true;
opts->textarea.obscured = true;
opts->textarea.bullet = LV_SYMBOL_BULLET;
opts->theme.default_id = UL_THEMES_THEME_BREEZY_DARK;
opts->theme.alternate_id = UL_THEMES_THEME_BREEZY_LIGHT;
opts->input.keyboard = true;
opts->input.pointer = true;
opts->input.touchscreen = true;
}
void ul_config_parse_directory(const char *path, ul_config_opts *opts) {
/* Find files in directory */
char **found = NULL;
int num_found = 0;
find_files(path, &found, &num_found);
/* Sort and parse files */
qsort(found, num_found, sizeof(char *), compare_strings);
ul_config_parse_files((const char **)found, num_found, opts);
/* Free memory */
for (int i = 0; i < num_found; ++i) {
free(found[i]);
}
free(found);
}
void ul_config_parse_files(const char **files, int num_files, ul_config_opts *opts) {
for (int i = 0; i < num_files; ++i) {
parse_file(files[i], opts);
ul_config_parse_file(files[i], opts);
}
}
void ul_config_parse_file(const char *path, ul_config_opts *opts) {
ul_log(UL_LOG_LEVEL_VERBOSE, "Parsing config file %s", path);
if (ini_parse(path, parsing_handler, opts) != 0) {
ul_log(UL_LOG_LEVEL_ERROR, "Ignoring invalid config file %s", path);
}
}

View File

@@ -103,12 +103,35 @@ typedef struct {
} ul_config_opts;
/**
* Parse options from one or more configuration files.
* Initialise a config options struct with default values.
*
* @param opts pointer to the options struct
*/
void ul_config_init_opts(ul_config_opts *opts);
/**
* Find configuration files in a directory and parse them in alphabetic order.
*
* @param path directory path
* @param opts pointer for writing the parsed options into
*/
void ul_config_parse_directory(const char *path, ul_config_opts *opts);
/**
* Parse one or more configuration files.
*
* @param files paths to configuration files
* @param num_files number of configuration files
* @param opts pointer for writing the parsed options into
*/
void ul_config_parse(const char **files, int num_files, ul_config_opts *opts);
void ul_config_parse_files(const char **files, int num_files, ul_config_opts *opts);
/**
* Parse a configuration file.
*
* @param path path to configuration file
* @param opts pointer for writing the parsed options into
*/
void ul_config_parse_file(const char *path, ul_config_opts *opts);
#endif /* UL_CONFIG_H */

5
main.c
View File

@@ -351,7 +351,10 @@ int main(int argc, char *argv[]) {
ul_log(UL_LOG_LEVEL_VERBOSE, "unl0kr %s", UL_VERSION);
/* Parse config files */
ul_config_parse(cli_opts.config_files, cli_opts.num_config_files, &conf_opts);
ul_config_init_opts(&conf_opts);
ul_config_parse_file("/etc/unl0kr.conf", &conf_opts);
ul_config_parse_directory("/etc/unl0kr.conf.d", &conf_opts);
ul_config_parse_files(cli_opts.config_files, cli_opts.num_config_files, &conf_opts);
/* Prepare current TTY and clean up on termination */
ul_terminal_prepare_current_terminal();