]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/shared/kbd-util.c
Merge pull request #18891 from keszybz/size_t-cast-removal
[thirdparty/systemd.git] / src / shared / kbd-util.c
1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2
3 #include <ftw.h>
4
5 #include "errno-util.h"
6 #include "kbd-util.h"
7 #include "log.h"
8 #include "nulstr-util.h"
9 #include "path-util.h"
10 #include "set.h"
11 #include "string-util.h"
12 #include "strv.h"
13 #include "utf8.h"
14
15 static thread_local const char *keymap_name = NULL;
16 static thread_local Set *keymaps = NULL;
17
18 static int nftw_cb(
19 const char *fpath,
20 const struct stat *sb,
21 int tflag,
22 struct FTW *ftwbuf) {
23
24 _cleanup_free_ char *p = NULL;
25 int r;
26
27 /* If keymap_name is non-null, return true if keymap keymap_name is found.
28 * Otherwise, add all keymaps to keymaps. */
29
30 if (tflag != FTW_F)
31 return 0;
32
33 fpath = basename(fpath);
34
35 const char *e = endswith(fpath, ".map") ?: endswith(fpath, ".map.gz");
36 if (!e)
37 return 0;
38
39 p = strndup(fpath, e - fpath);
40 if (!p) {
41 errno = ENOMEM;
42 return -1;
43 }
44
45 if (keymap_name)
46 return streq(p, keymap_name);
47
48 if (!keymap_is_valid(p))
49 return 0;
50
51 r = set_consume(keymaps, TAKE_PTR(p));
52 if (r < 0 && r != -EEXIST) {
53 errno = -r;
54 return -1;
55 }
56
57 return 0;
58 }
59
60 int get_keymaps(char ***ret) {
61 keymaps = set_new(&string_hash_ops);
62 if (!keymaps)
63 return -ENOMEM;
64
65 const char *dir;
66 NULSTR_FOREACH(dir, KBD_KEYMAP_DIRS)
67 if (nftw(dir, nftw_cb, 20, FTW_PHYS) < 0) {
68 if (errno == ENOENT)
69 continue;
70 if (ERRNO_IS_RESOURCE(errno)) {
71 keymaps = set_free_free(keymaps);
72 return log_warning_errno(errno, "Failed to read keymap list from %s: %m", dir);
73 }
74 log_debug_errno(errno, "Failed to read keymap list from %s, ignoring: %m", dir);
75 }
76
77 _cleanup_strv_free_ char **l = set_get_strv(keymaps);
78 if (!l) {
79 keymaps = set_free_free(keymaps);
80 return -ENOMEM;
81 }
82
83 keymaps = set_free(keymaps);
84
85 if (strv_isempty(l))
86 return -ENOENT;
87
88 strv_sort(l);
89
90 *ret = TAKE_PTR(l);
91
92 return 0;
93 }
94
95 bool keymap_is_valid(const char *name) {
96 if (isempty(name))
97 return false;
98
99 if (strlen(name) >= 128)
100 return false;
101
102 if (!utf8_is_valid(name))
103 return false;
104
105 if (!filename_is_valid(name))
106 return false;
107
108 if (!string_is_safe(name))
109 return false;
110
111 return true;
112 }
113
114 int keymap_exists(const char *name) {
115 int r = 0;
116
117 if (!keymap_is_valid(name))
118 return -EINVAL;
119
120 keymap_name = name;
121
122 const char *dir;
123 NULSTR_FOREACH(dir, KBD_KEYMAP_DIRS) {
124 r = nftw(dir, nftw_cb, 20, FTW_PHYS);
125 if (r > 0)
126 break;
127 if (r < 0 && errno != ENOENT)
128 log_debug_errno(errno, "Failed to read keymap list from %s, ignoring: %m", dir);
129 }
130
131 keymap_name = NULL;
132
133 return r > 0;
134 }