Override config from conf.d
This commit is contained in:
@@ -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)
|
||||
|
||||
|
29
README.md
29
README.md
@@ -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].
|
||||
|
@@ -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) {
|
||||
|
155
config.c
155
config.c
@@ -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.
|
||||
*
|
||||
* @param opts pointer to the options struct
|
||||
* Compares two strings from opaque types.
|
||||
*
|
||||
* @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.
|
||||
*
|
||||
* @param path path to configuration file
|
||||
* @param opts pointer for writing the parsed options into
|
||||
* Checks whether a string ends with a suffix
|
||||
*
|
||||
* @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);
|
||||
}
|
||||
}
|
||||
|
27
config.h
27
config.h
@@ -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
5
main.c
@@ -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();
|
||||
|
Reference in New Issue
Block a user