]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/shared/kbd-util.c
man: Remove OSConfig project mentioning for systemd-confext
[thirdparty/systemd.git] / src / shared / kbd-util.c
CommitLineData
db9ecf05 1/* SPDX-License-Identifier: LGPL-2.1-or-later */
f05e1d0d 2
e852f10c 3#include "env-util.h"
1d230090 4#include "errno-util.h"
f05e1d0d
LP
5#include "kbd-util.h"
6#include "log.h"
7#include "path-util.h"
fef4fe1a 8#include "recurse-dir.h"
f05e1d0d
LP
9#include "set.h"
10#include "string-util.h"
11#include "strv.h"
12#include "utf8.h"
13
e852f10c
YW
14#define KBD_KEYMAP_DIRS \
15 "/usr/share/keymaps/", \
16 "/usr/share/kbd/keymaps/", \
17 "/usr/lib/kbd/keymaps/"
18
19int keymap_directories(char ***ret) {
20 assert(ret);
21
22 if (getenv_path_list("SYSTEMD_KEYMAP_DIRECTORIES", ret) >= 0)
23 return 0;
24
25 char **paths = strv_new(KBD_KEYMAP_DIRS);
26 if (!paths)
27 return log_oom_debug();
28
29 *ret = TAKE_PTR(paths);
30 return 0;
31}
32
fef4fe1a
LP
33struct recurse_dir_userdata {
34 const char *keymap_name;
35 Set *keymaps;
36};
37
38static int keymap_recurse_dir_callback(
39 RecurseDirEvent event,
40 const char *path,
41 int dir_fd,
42 int inode_fd,
43 const struct dirent *de,
44 const struct statx *sx,
45 void *userdata) {
46
47 struct recurse_dir_userdata *data = userdata;
f05e1d0d 48 _cleanup_free_ char *p = NULL;
f05e1d0d
LP
49 int r;
50
fef4fe1a 51 assert(de);
9ef70c06 52
fef4fe1a
LP
53 /* If 'keymap_name' is non-NULL, return true if keymap 'keymap_name' is found. Otherwise, add all
54 * keymaps to 'keymaps'. */
55
56 if (event != RECURSE_DIR_ENTRY)
57 return RECURSE_DIR_CONTINUE;
f05e1d0d 58
fef4fe1a
LP
59 if (!IN_SET(de->d_type, DT_REG, DT_LNK))
60 return RECURSE_DIR_CONTINUE;
73d0806a 61
fef4fe1a 62 const char *e = endswith(de->d_name, ".map") ?: endswith(de->d_name, ".map.gz");
73d0806a 63 if (!e)
fef4fe1a 64 return RECURSE_DIR_CONTINUE;
f05e1d0d 65
fef4fe1a
LP
66 p = strndup(de->d_name, e - de->d_name);
67 if (!p)
68 return -ENOMEM;
69
70 if (data->keymap_name)
71 return streq(p, data->keymap_name) ? 1 : RECURSE_DIR_CONTINUE;
f05e1d0d 72
fef4fe1a 73 assert(data->keymaps);
9ef70c06 74
f05e1d0d
LP
75 if (!keymap_is_valid(p))
76 return 0;
77
fef4fe1a
LP
78 r = set_consume(data->keymaps, TAKE_PTR(p));
79 if (r < 0)
80 return r;
f05e1d0d 81
fef4fe1a 82 return RECURSE_DIR_CONTINUE;
f05e1d0d
LP
83}
84
85int get_keymaps(char ***ret) {
5d2a48da 86 _cleanup_set_free_free_ Set *keymaps = NULL;
e852f10c 87 _cleanup_strv_free_ char **keymap_dirs = NULL;
fef4fe1a
LP
88 int r;
89
e852f10c
YW
90 r = keymap_directories(&keymap_dirs);
91 if (r < 0)
92 return r;
93
f05e1d0d
LP
94 keymaps = set_new(&string_hash_ops);
95 if (!keymaps)
96 return -ENOMEM;
97
e852f10c 98 STRV_FOREACH(dir, keymap_dirs) {
fef4fe1a
LP
99 r = recurse_dir_at(
100 AT_FDCWD,
e852f10c 101 *dir,
fef4fe1a
LP
102 /* statx_mask= */ 0,
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) {
107 .keymaps = keymaps,
108 });
bb44fd07
ZJS
109 if (r == -ENOENT)
110 continue;
111 if (ERRNO_IS_NEG_RESOURCE(r))
e852f10c 112 return log_warning_errno(r, "Failed to read keymap list from %s: %m", *dir);
bb44fd07 113 if (r < 0)
e852f10c 114 log_debug_errno(r, "Failed to read keymap list from %s, ignoring: %m", *dir);
fef4fe1a 115 }
f05e1d0d 116
3864b4b0 117 _cleanup_strv_free_ char **l = set_get_strv(keymaps);
fef4fe1a 118 if (!l)
f05e1d0d 119 return -ENOMEM;
f05e1d0d 120
fef4fe1a
LP
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
123 * strv */
f05e1d0d
LP
124
125 if (strv_isempty(l))
126 return -ENOENT;
127
128 strv_sort(l);
129
130 *ret = TAKE_PTR(l);
f05e1d0d
LP
131 return 0;
132}
133
134bool keymap_is_valid(const char *name) {
f05e1d0d
LP
135 if (isempty(name))
136 return false;
137
138 if (strlen(name) >= 128)
139 return false;
140
141 if (!utf8_is_valid(name))
142 return false;
143
144 if (!filename_is_valid(name))
145 return false;
146
147 if (!string_is_safe(name))
148 return false;
149
150 return true;
151}
9ef70c06
ZJS
152
153int keymap_exists(const char *name) {
e852f10c 154 _cleanup_strv_free_ char **keymap_dirs = NULL;
7d01eb35 155 int r;
9ef70c06
ZJS
156
157 if (!keymap_is_valid(name))
158 return -EINVAL;
159
e852f10c
YW
160 r = keymap_directories(&keymap_dirs);
161 if (r < 0)
162 return r;
163
164 STRV_FOREACH(dir, keymap_dirs) {
fef4fe1a
LP
165 r = recurse_dir_at(
166 AT_FDCWD,
e852f10c 167 *dir,
fef4fe1a
LP
168 /* statx_mask= */ 0,
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) {
173 .keymap_name = name,
174 });
9ef70c06 175 if (r > 0)
7d01eb35
ZJS
176 return true;
177 if (ERRNO_IS_NEG_RESOURCE(r))
178 return r;
179 if (r < 0 && r != -ENOENT)
e852f10c 180 log_debug_errno(r, "Failed to read keymap list from %s, ignoring: %m", *dir);
9ef70c06
ZJS
181 }
182
7d01eb35 183 return false;
9ef70c06 184}