From e852f10cb4a4bf8f2a735d133c6f45a4abbde5af Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Thu, 14 Mar 2024 18:40:14 +0900 Subject: [PATCH] kbd-util: allow to override the default keymap directories This introduces $SYSTEMD_KEYMAP_DIRECTORIES environment variable to override the hardcoded keymap directories. I think it is not necessary to provide the first class configuration option for controlling the keymap directories, but it is not good to hardcode the paths. So, let's introduce an environment variable to override that. Prompted by #31759. Closes #31759. --- docs/ENVIRONMENT.md | 7 +++++- src/locale/localed-util.c | 14 ++++++++---- src/shared/kbd-util.c | 45 ++++++++++++++++++++++++++++++++------- src/shared/kbd-util.h | 8 ++----- 4 files changed, 55 insertions(+), 19 deletions(-) diff --git a/docs/ENVIRONMENT.md b/docs/ENVIRONMENT.md index cd6d66a81f1..cb2c6a8df51 100644 --- a/docs/ENVIRONMENT.md +++ b/docs/ENVIRONMENT.md @@ -348,12 +348,17 @@ All tools: `systemd-gpt-auto-generator` to ensure the root partition is mounted writable in accordance to the GPT partition flags. -`systemd-firstboot` and `localectl`: +`systemd-firstboot`, `localectl`, and `systemd-localed`: * `$SYSTEMD_LIST_NON_UTF8_LOCALES=1` — if set, non-UTF-8 locales are listed among the installed ones. By default non-UTF-8 locales are suppressed from the selection, since we are living in the 21st century. +* `$SYSTEMD_KEYMAP_DIRECTORIES=` — takes a colon (`:`) separated list of keymap + directories. The directories must be absolute and normalized. If unset, the + default keymap directories (/usr/share/keymaps/, /usr/share/kbd/keymaps/, and + /usr/lib/kbd/keymaps/) will be used. + `systemd-resolved`: * `$SYSTEMD_RESOLVED_SYNTHESIZE_HOSTNAME` — if set to "0", `systemd-resolved` diff --git a/src/locale/localed-util.c b/src/locale/localed-util.c index de88df163d0..56996596fe1 100644 --- a/src/locale/localed-util.c +++ b/src/locale/localed-util.c @@ -736,6 +736,8 @@ int vconsole_convert_to_x11(const VCContext *vc, X11Context *ret) { int find_converted_keymap(const X11Context *xc, char **ret) { _cleanup_free_ char *n = NULL, *p = NULL, *pz = NULL; + _cleanup_strv_free_ char **keymap_dirs = NULL; + int r; assert(xc); assert(!isempty(xc->layout)); @@ -753,20 +755,24 @@ int find_converted_keymap(const X11Context *xc, char **ret) { if (!p || !pz) return -ENOMEM; - NULSTR_FOREACH(dir, KBD_KEYMAP_DIRS) { + r = keymap_directories(&keymap_dirs); + if (r < 0) + return r; + + STRV_FOREACH(dir, keymap_dirs) { _cleanup_close_ int dir_fd = -EBADF; bool uncompressed; - dir_fd = open(dir, O_CLOEXEC | O_DIRECTORY | O_PATH); + dir_fd = open(*dir, O_CLOEXEC | O_DIRECTORY | O_PATH); if (dir_fd < 0) { if (errno != ENOENT) - log_debug_errno(errno, "Failed to open %s, ignoring: %m", dir); + log_debug_errno(errno, "Failed to open %s, ignoring: %m", *dir); continue; } uncompressed = faccessat(dir_fd, p, F_OK, 0) >= 0; if (uncompressed || faccessat(dir_fd, pz, F_OK, 0) >= 0) { - log_debug("Found converted keymap %s at %s/%s", n, dir, uncompressed ? p : pz); + log_debug("Found converted keymap %s at %s/%s", n, *dir, uncompressed ? p : pz); *ret = TAKE_PTR(n); return 1; } diff --git a/src/shared/kbd-util.c b/src/shared/kbd-util.c index 2f2d161ca68..60e0429b82a 100644 --- a/src/shared/kbd-util.c +++ b/src/shared/kbd-util.c @@ -1,9 +1,9 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ +#include "env-util.h" #include "errno-util.h" #include "kbd-util.h" #include "log.h" -#include "nulstr-util.h" #include "path-util.h" #include "recurse-dir.h" #include "set.h" @@ -11,6 +11,25 @@ #include "strv.h" #include "utf8.h" +#define KBD_KEYMAP_DIRS \ + "/usr/share/keymaps/", \ + "/usr/share/kbd/keymaps/", \ + "/usr/lib/kbd/keymaps/" + +int keymap_directories(char ***ret) { + assert(ret); + + if (getenv_path_list("SYSTEMD_KEYMAP_DIRECTORIES", ret) >= 0) + return 0; + + char **paths = strv_new(KBD_KEYMAP_DIRS); + if (!paths) + return log_oom_debug(); + + *ret = TAKE_PTR(paths); + return 0; +} + struct recurse_dir_userdata { const char *keymap_name; Set *keymaps; @@ -65,16 +84,21 @@ static int keymap_recurse_dir_callback( int get_keymaps(char ***ret) { _cleanup_set_free_free_ Set *keymaps = NULL; + _cleanup_strv_free_ char **keymap_dirs = NULL; int r; + r = keymap_directories(&keymap_dirs); + if (r < 0) + return r; + keymaps = set_new(&string_hash_ops); if (!keymaps) return -ENOMEM; - NULSTR_FOREACH(dir, KBD_KEYMAP_DIRS) { + STRV_FOREACH(dir, keymap_dirs) { r = recurse_dir_at( AT_FDCWD, - dir, + *dir, /* statx_mask= */ 0, /* n_depth_max= */ UINT_MAX, RECURSE_DIR_IGNORE_DOT|RECURSE_DIR_ENSURE_TYPE, @@ -85,9 +109,9 @@ int get_keymaps(char ***ret) { if (r == -ENOENT) continue; if (ERRNO_IS_NEG_RESOURCE(r)) - return log_warning_errno(r, "Failed to read keymap list from %s: %m", dir); + return log_warning_errno(r, "Failed to read keymap list from %s: %m", *dir); if (r < 0) - log_debug_errno(r, "Failed to read keymap list from %s, ignoring: %m", dir); + log_debug_errno(r, "Failed to read keymap list from %s, ignoring: %m", *dir); } _cleanup_strv_free_ char **l = set_get_strv(keymaps); @@ -127,15 +151,20 @@ bool keymap_is_valid(const char *name) { } int keymap_exists(const char *name) { + _cleanup_strv_free_ char **keymap_dirs = NULL; int r; if (!keymap_is_valid(name)) return -EINVAL; - NULSTR_FOREACH(dir, KBD_KEYMAP_DIRS) { + r = keymap_directories(&keymap_dirs); + if (r < 0) + return r; + + STRV_FOREACH(dir, keymap_dirs) { r = recurse_dir_at( AT_FDCWD, - dir, + *dir, /* statx_mask= */ 0, /* n_depth_max= */ UINT_MAX, RECURSE_DIR_IGNORE_DOT|RECURSE_DIR_ENSURE_TYPE, @@ -148,7 +177,7 @@ int keymap_exists(const char *name) { if (ERRNO_IS_NEG_RESOURCE(r)) return r; if (r < 0 && r != -ENOENT) - log_debug_errno(r, "Failed to read keymap list from %s, ignoring: %m", dir); + log_debug_errno(r, "Failed to read keymap list from %s, ignoring: %m", *dir); } return false; diff --git a/src/shared/kbd-util.h b/src/shared/kbd-util.h index aca0dee4bc0..a8e365e3ca4 100644 --- a/src/shared/kbd-util.h +++ b/src/shared/kbd-util.h @@ -3,11 +3,7 @@ #include -#define KBD_KEYMAP_DIRS \ - "/usr/share/keymaps/\0" \ - "/usr/share/kbd/keymaps/\0" \ - "/usr/lib/kbd/keymaps/\0" - -int get_keymaps(char ***l); +int keymap_directories(char ***ret); +int get_keymaps(char ***ret); bool keymap_is_valid(const char *name); int keymap_exists(const char *name); -- 2.47.3