From fef4fe1a8470db2498fef787b11755c3725f7ad9 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 1 Oct 2021 15:55:53 +0200 Subject: [PATCH] kbd-util: port from nftw() to recurse_dir() --- src/shared/kbd-util.c | 131 ++++++++++++++++++++++++--------------- src/test/meson.build | 2 + src/test/test-kbd-util.c | 28 +++++++++ 3 files changed, 110 insertions(+), 51 deletions(-) create mode 100644 src/test/test-kbd-util.c diff --git a/src/shared/kbd-util.c b/src/shared/kbd-util.c index 92abaea65e1..842ff3066b4 100644 --- a/src/shared/kbd-util.c +++ b/src/shared/kbd-util.c @@ -1,86 +1,105 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ -#include - #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" #include "string-util.h" #include "strv.h" #include "utf8.h" -static thread_local const char *keymap_name = NULL; -static thread_local Set *keymaps = NULL; +struct recurse_dir_userdata { + const char *keymap_name; + Set *keymaps; +}; -static int nftw_cb( - const char *fpath, - const struct stat *sb, - int tflag, - struct FTW *ftwbuf) { +static int keymap_recurse_dir_callback( + RecurseDirEvent event, + const char *path, + int dir_fd, + int inode_fd, + const struct dirent *de, + const struct statx *sx, + void *userdata) { + struct recurse_dir_userdata *data = userdata; _cleanup_free_ char *p = NULL; int r; - /* If keymap_name is non-null, return true if keymap keymap_name is found. - * Otherwise, add all keymaps to keymaps. */ + assert(de); - if (tflag != FTW_F) - return 0; + /* If 'keymap_name' is non-NULL, return true if keymap 'keymap_name' is found. Otherwise, add all + * keymaps to 'keymaps'. */ - fpath = basename(fpath); + if (event != RECURSE_DIR_ENTRY) + return RECURSE_DIR_CONTINUE; - const char *e = endswith(fpath, ".map") ?: endswith(fpath, ".map.gz"); + if (!IN_SET(de->d_type, DT_REG, DT_LNK)) + return RECURSE_DIR_CONTINUE; + + const char *e = endswith(de->d_name, ".map") ?: endswith(de->d_name, ".map.gz"); if (!e) - return 0; + return RECURSE_DIR_CONTINUE; - p = strndup(fpath, e - fpath); - if (!p) { - errno = ENOMEM; - return -1; - } + p = strndup(de->d_name, e - de->d_name); + if (!p) + return -ENOMEM; - if (keymap_name) - return streq(p, keymap_name); + if (data->keymap_name) + return streq(p, data->keymap_name) ? 1 : RECURSE_DIR_CONTINUE; + + assert(data->keymaps); if (!keymap_is_valid(p)) return 0; - r = set_consume(keymaps, TAKE_PTR(p)); - if (r < 0 && r != -EEXIST) { - errno = -r; - return -1; - } + r = set_consume(data->keymaps, TAKE_PTR(p)); + if (r < 0) + return r; - return 0; + return RECURSE_DIR_CONTINUE; } int get_keymaps(char ***ret) { + _cleanup_(set_free_freep) Set *keymaps = NULL; + int r; + keymaps = set_new(&string_hash_ops); if (!keymaps) return -ENOMEM; const char *dir; - NULSTR_FOREACH(dir, KBD_KEYMAP_DIRS) - if (nftw(dir, nftw_cb, 20, FTW_PHYS) < 0) { - if (errno == ENOENT) + NULSTR_FOREACH(dir, KBD_KEYMAP_DIRS) { + r = recurse_dir_at( + AT_FDCWD, + dir, + /* statx_mask= */ 0, + /* n_depth_max= */ UINT_MAX, + RECURSE_DIR_IGNORE_DOT|RECURSE_DIR_ENSURE_TYPE, + keymap_recurse_dir_callback, + &(struct recurse_dir_userdata) { + .keymaps = keymaps, + }); + if (r < 0) { + if (r == -ENOENT) continue; - if (ERRNO_IS_RESOURCE(errno)) { - keymaps = set_free_free(keymaps); - return log_warning_errno(errno, "Failed to read keymap list from %s: %m", dir); - } - log_debug_errno(errno, "Failed to read keymap list from %s, ignoring: %m", dir); - } + if (ERRNO_IS_RESOURCE(r)) + return log_warning_errno(r, "Failed to read keymap list from %s: %m", dir); - _cleanup_strv_free_ char **l = set_get_strv(keymaps); - if (!l) { - keymaps = set_free_free(keymaps); - return -ENOMEM; + log_debug_errno(r, "Failed to read keymap list from %s, ignoring: %m", dir); + } } - keymaps = set_free(keymaps); + _cleanup_strv_free_ char **l = set_get_strv(keymaps); + if (!l) + return -ENOMEM; + + keymaps = set_free(keymaps); /* If we got the strv above, then do a set_free() rather than + * set_free_free() since the entries of the set are now owned by the + * strv */ if (strv_isempty(l)) return -ENOENT; @@ -88,7 +107,6 @@ int get_keymaps(char ***ret) { strv_sort(l); *ret = TAKE_PTR(l); - return 0; } @@ -117,18 +135,29 @@ int keymap_exists(const char *name) { if (!keymap_is_valid(name)) return -EINVAL; - keymap_name = name; - const char *dir; NULSTR_FOREACH(dir, KBD_KEYMAP_DIRS) { - r = nftw(dir, nftw_cb, 20, FTW_PHYS); + r = recurse_dir_at( + AT_FDCWD, + dir, + /* statx_mask= */ 0, + /* n_depth_max= */ UINT_MAX, + RECURSE_DIR_IGNORE_DOT|RECURSE_DIR_ENSURE_TYPE, + keymap_recurse_dir_callback, + &(struct recurse_dir_userdata) { + .keymap_name = name, + }); + if (r == -ENOENT) + continue; + if (ERRNO_IS_RESOURCE(r)) + return r; + if (r < 0) { + log_debug_errno(r, "Failed to read keymap list from %s, ignoring: %m", dir); + continue; + } if (r > 0) break; - if (r < 0 && errno != ENOENT) - log_debug_errno(errno, "Failed to read keymap list from %s, ignoring: %m", dir); } - keymap_name = NULL; - return r > 0; } diff --git a/src/test/meson.build b/src/test/meson.build index 534e3d1924f..fea7f107fd5 100644 --- a/src/test/meson.build +++ b/src/test/meson.build @@ -148,6 +148,8 @@ tests += [ [['src/test/test-utf8.c']], + [['src/test/test-kbd-util.c']], + [['src/test/test-blockdev-util.c']], [['src/test/test-dev-setup.c']], diff --git a/src/test/test-kbd-util.c b/src/test/test-kbd-util.c new file mode 100644 index 00000000000..c7b4b842c02 --- /dev/null +++ b/src/test/test-kbd-util.c @@ -0,0 +1,28 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ + +#include "kbd-util.h" +#include "log.h" +#include "strv.h" +#include "tests.h" + +int main(int argc, char *argv[]) { + _cleanup_strv_free_ char **maps = NULL; + char **m; + int r; + + log_show_color(true); + test_setup_logging(LOG_DEBUG); + + r = get_keymaps(&maps); + if (r < 0) { + log_error_errno(r, "Failed to aquire keymaps: %m"); + return 0; + } + + STRV_FOREACH(m, maps) { + log_info("Found keymap: %s", *m); + assert_se(keymap_exists(*m) > 0); + } + + return 0; +}