1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
4 #include "errno-util.h"
8 #include "recurse-dir.h"
10 #include "string-util.h"
14 #define KBD_KEYMAP_DIRS \
15 "/usr/share/keymaps/", \
16 "/usr/share/kbd/keymaps/", \
17 "/usr/lib/kbd/keymaps/"
19 int keymap_directories(char ***ret
) {
22 if (getenv_path_list("SYSTEMD_KEYMAP_DIRECTORIES", ret
) >= 0)
25 char **paths
= strv_new(KBD_KEYMAP_DIRS
);
27 return log_oom_debug();
29 *ret
= TAKE_PTR(paths
);
33 struct recurse_dir_userdata
{
34 const char *keymap_name
;
38 static int keymap_recurse_dir_callback(
39 RecurseDirEvent event
,
43 const struct dirent
*de
,
44 const struct statx
*sx
,
47 struct recurse_dir_userdata
*data
= userdata
;
48 _cleanup_free_
char *p
= NULL
;
53 /* If 'keymap_name' is non-NULL, return true if keymap 'keymap_name' is found. Otherwise, add all
54 * keymaps to 'keymaps'. */
56 if (event
!= RECURSE_DIR_ENTRY
)
57 return RECURSE_DIR_CONTINUE
;
59 if (!IN_SET(de
->d_type
, DT_REG
, DT_LNK
))
60 return RECURSE_DIR_CONTINUE
;
62 const char *e
= endswith(de
->d_name
, ".map") ?: endswith(de
->d_name
, ".map.gz");
64 return RECURSE_DIR_CONTINUE
;
66 p
= strndup(de
->d_name
, e
- de
->d_name
);
70 if (data
->keymap_name
)
71 return streq(p
, data
->keymap_name
) ? 1 : RECURSE_DIR_CONTINUE
;
73 assert(data
->keymaps
);
75 if (!keymap_is_valid(p
))
78 r
= set_consume(data
->keymaps
, TAKE_PTR(p
));
82 return RECURSE_DIR_CONTINUE
;
85 int get_keymaps(char ***ret
) {
86 _cleanup_set_free_free_ Set
*keymaps
= NULL
;
87 _cleanup_strv_free_
char **keymap_dirs
= NULL
;
90 r
= keymap_directories(&keymap_dirs
);
94 keymaps
= set_new(&string_hash_ops
);
98 STRV_FOREACH(dir
, keymap_dirs
) {
103 /* n_depth_max= */ UINT_MAX
,
104 RECURSE_DIR_IGNORE_DOT
|RECURSE_DIR_ENSURE_TYPE
,
105 keymap_recurse_dir_callback
,
106 &(struct recurse_dir_userdata
) {
111 if (ERRNO_IS_NEG_RESOURCE(r
))
112 return log_warning_errno(r
, "Failed to read keymap list from %s: %m", *dir
);
114 log_debug_errno(r
, "Failed to read keymap list from %s, ignoring: %m", *dir
);
117 _cleanup_strv_free_
char **l
= set_get_strv(keymaps
);
121 keymaps
= set_free(keymaps
); /* If we got the strv above, then do a set_free() rather than
122 * set_free_free() since the entries of the set are now owned by the
134 bool keymap_is_valid(const char *name
) {
138 if (strlen(name
) >= 128)
141 if (!utf8_is_valid(name
))
144 if (!filename_is_valid(name
))
147 if (!string_is_safe(name
))
153 int keymap_exists(const char *name
) {
154 _cleanup_strv_free_
char **keymap_dirs
= NULL
;
157 if (!keymap_is_valid(name
))
160 r
= keymap_directories(&keymap_dirs
);
164 STRV_FOREACH(dir
, keymap_dirs
) {
169 /* n_depth_max= */ UINT_MAX
,
170 RECURSE_DIR_IGNORE_DOT
|RECURSE_DIR_ENSURE_TYPE
,
171 keymap_recurse_dir_callback
,
172 &(struct recurse_dir_userdata
) {
177 if (ERRNO_IS_NEG_RESOURCE(r
))
179 if (r
< 0 && r
!= -ENOENT
)
180 log_debug_errno(r
, "Failed to read keymap list from %s, ignoring: %m", *dir
);