File: | build-scan/../src/locale/keymap-util.c |
Warning: | line 628, column 21 Array access (from variable 'a') results in a null pointer dereference |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* SPDX-License-Identifier: LGPL-2.1+ */ | |||
2 | ||||
3 | #include <errno(*__errno_location ()).h> | |||
4 | #include <stdio_ext.h> | |||
5 | #include <string.h> | |||
6 | #include <unistd.h> | |||
7 | ||||
8 | #include "def.h" | |||
9 | #include "env-util.h" | |||
10 | #include "fd-util.h" | |||
11 | #include "fileio-label.h" | |||
12 | #include "fileio.h" | |||
13 | #include "keymap-util.h" | |||
14 | #include "locale-util.h" | |||
15 | #include "macro.h" | |||
16 | #include "mkdir.h" | |||
17 | #include "string-util.h" | |||
18 | #include "strv.h" | |||
19 | ||||
20 | static bool_Bool startswith_comma(const char *s, const char *prefix) { | |||
21 | s = startswith(s, prefix); | |||
22 | if (!s) | |||
23 | return false0; | |||
24 | ||||
25 | return IN_SET(*s, ',', '\0')({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended [20 - sizeof((int[]){',', '\0'})/sizeof(int)]; switch(*s) { case ',': case '\0': _found = 1; break; default: break; } _found; }); | |||
26 | } | |||
27 | ||||
28 | static const char* strnulldash(const char *s) { | |||
29 | return isempty(s) || streq(s, "-")(strcmp((s),("-")) == 0) ? NULL((void*)0) : s; | |||
30 | } | |||
31 | ||||
32 | static const char* systemd_kbd_model_map(void) { | |||
33 | const char* s; | |||
34 | ||||
35 | s = getenv("SYSTEMD_KBD_MODEL_MAP"); | |||
36 | if (s) | |||
37 | return s; | |||
38 | ||||
39 | return SYSTEMD_KBD_MODEL_MAP"/usr/share/systemd/kbd-model-map"; | |||
40 | } | |||
41 | ||||
42 | static const char* systemd_language_fallback_map(void) { | |||
43 | const char* s; | |||
44 | ||||
45 | s = getenv("SYSTEMD_LANGUAGE_FALLBACK_MAP"); | |||
46 | if (s) | |||
47 | return s; | |||
48 | ||||
49 | return SYSTEMD_LANGUAGE_FALLBACK_MAP"/usr/share/systemd/language-fallback-map"; | |||
50 | } | |||
51 | ||||
52 | static void context_free_x11(Context *c) { | |||
53 | c->x11_layout = mfree(c->x11_layout); | |||
54 | c->x11_options = mfree(c->x11_options); | |||
55 | c->x11_model = mfree(c->x11_model); | |||
56 | c->x11_variant = mfree(c->x11_variant); | |||
57 | } | |||
58 | ||||
59 | static void context_free_vconsole(Context *c) { | |||
60 | c->vc_keymap = mfree(c->vc_keymap); | |||
61 | c->vc_keymap_toggle = mfree(c->vc_keymap_toggle); | |||
62 | } | |||
63 | ||||
64 | static void context_free_locale(Context *c) { | |||
65 | int p; | |||
66 | ||||
67 | for (p = 0; p < _VARIABLE_LC_MAX; p++) | |||
68 | c->locale[p] = mfree(c->locale[p]); | |||
69 | } | |||
70 | ||||
71 | void context_free(Context *c) { | |||
72 | context_free_locale(c); | |||
73 | context_free_x11(c); | |||
74 | context_free_vconsole(c); | |||
75 | }; | |||
76 | ||||
77 | void locale_simplify(char *locale[_VARIABLE_LC_MAX]) { | |||
78 | int p; | |||
79 | ||||
80 | for (p = VARIABLE_LANG+1; p < _VARIABLE_LC_MAX; p++) | |||
81 | if (isempty(locale[p]) || streq_ptr(locale[VARIABLE_LANG], locale[p])) | |||
82 | locale[p] = mfree(locale[p]); | |||
83 | } | |||
84 | ||||
85 | int locale_read_data(Context *c, sd_bus_message *m) { | |||
86 | struct stat st; | |||
87 | int r; | |||
88 | ||||
89 | /* Do not try to re-read the file within single bus operation. */ | |||
90 | if (m && m == c->locale_cache) | |||
91 | return 0; | |||
92 | ||||
93 | /* To suppress multiple call of stat(), store the message to cache here. */ | |||
94 | c->locale_cache = m; | |||
95 | ||||
96 | r = stat("/etc/locale.conf", &st); | |||
97 | if (r < 0 && errno(*__errno_location ()) != ENOENT2) | |||
98 | return -errno(*__errno_location ()); | |||
99 | ||||
100 | if (r >= 0) { | |||
101 | usec_t t; | |||
102 | ||||
103 | /* If mtime is not changed, then we do not need to re-read the file. */ | |||
104 | t = timespec_load(&st.st_mtim); | |||
105 | if (c->locale_mtime != USEC_INFINITY((usec_t) -1) && t == c->locale_mtime) | |||
106 | return 0; | |||
107 | ||||
108 | c->locale_mtime = t; | |||
109 | context_free_locale(c); | |||
110 | ||||
111 | r = parse_env_file(NULL((void*)0), "/etc/locale.conf", NEWLINE"\n\r", | |||
112 | "LANG", &c->locale[VARIABLE_LANG], | |||
113 | "LANGUAGE", &c->locale[VARIABLE_LANGUAGE], | |||
114 | "LC_CTYPE", &c->locale[VARIABLE_LC_CTYPE], | |||
115 | "LC_NUMERIC", &c->locale[VARIABLE_LC_NUMERIC], | |||
116 | "LC_TIME", &c->locale[VARIABLE_LC_TIME], | |||
117 | "LC_COLLATE", &c->locale[VARIABLE_LC_COLLATE], | |||
118 | "LC_MONETARY", &c->locale[VARIABLE_LC_MONETARY], | |||
119 | "LC_MESSAGES", &c->locale[VARIABLE_LC_MESSAGES], | |||
120 | "LC_PAPER", &c->locale[VARIABLE_LC_PAPER], | |||
121 | "LC_NAME", &c->locale[VARIABLE_LC_NAME], | |||
122 | "LC_ADDRESS", &c->locale[VARIABLE_LC_ADDRESS], | |||
123 | "LC_TELEPHONE", &c->locale[VARIABLE_LC_TELEPHONE], | |||
124 | "LC_MEASUREMENT", &c->locale[VARIABLE_LC_MEASUREMENT], | |||
125 | "LC_IDENTIFICATION", &c->locale[VARIABLE_LC_IDENTIFICATION], | |||
126 | NULL((void*)0)); | |||
127 | if (r < 0) | |||
128 | return r; | |||
129 | } else { | |||
130 | int p; | |||
131 | ||||
132 | c->locale_mtime = USEC_INFINITY((usec_t) -1); | |||
133 | context_free_locale(c); | |||
134 | ||||
135 | /* Fill in what we got passed from systemd. */ | |||
136 | for (p = 0; p < _VARIABLE_LC_MAX; p++) { | |||
137 | const char *name; | |||
138 | ||||
139 | name = locale_variable_to_string(p); | |||
140 | assert(name)do { if ((__builtin_expect(!!(!(name)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("name"), "../src/locale/keymap-util.c", 140 , __PRETTY_FUNCTION__); } while (0); | |||
141 | ||||
142 | r = free_and_strdup(&c->locale[p], empty_to_null(getenv(name))); | |||
143 | if (r < 0) | |||
144 | return r; | |||
145 | } | |||
146 | } | |||
147 | ||||
148 | locale_simplify(c->locale); | |||
149 | return 0; | |||
150 | } | |||
151 | ||||
152 | int vconsole_read_data(Context *c, sd_bus_message *m) { | |||
153 | struct stat st; | |||
154 | usec_t t; | |||
155 | int r; | |||
156 | ||||
157 | /* Do not try to re-read the file within single bus operation. */ | |||
158 | if (m && m == c->vc_cache) | |||
159 | return 0; | |||
160 | ||||
161 | /* To suppress multiple call of stat(), store the message to cache here. */ | |||
162 | c->vc_cache = m; | |||
163 | ||||
164 | if (stat("/etc/vconsole.conf", &st) < 0) { | |||
165 | if (errno(*__errno_location ()) != ENOENT2) | |||
166 | return -errno(*__errno_location ()); | |||
167 | ||||
168 | c->vc_mtime = USEC_INFINITY((usec_t) -1); | |||
169 | context_free_vconsole(c); | |||
170 | return 0; | |||
171 | } | |||
172 | ||||
173 | /* If mtime is not changed, then we do not need to re-read */ | |||
174 | t = timespec_load(&st.st_mtim); | |||
175 | if (c->vc_mtime != USEC_INFINITY((usec_t) -1) && t == c->vc_mtime) | |||
176 | return 0; | |||
177 | ||||
178 | c->vc_mtime = t; | |||
179 | context_free_vconsole(c); | |||
180 | ||||
181 | r = parse_env_file(NULL((void*)0), "/etc/vconsole.conf", NEWLINE"\n\r", | |||
182 | "KEYMAP", &c->vc_keymap, | |||
183 | "KEYMAP_TOGGLE", &c->vc_keymap_toggle, | |||
184 | NULL((void*)0)); | |||
185 | if (r < 0) | |||
186 | return r; | |||
187 | ||||
188 | return 0; | |||
189 | } | |||
190 | ||||
191 | int x11_read_data(Context *c, sd_bus_message *m) { | |||
192 | _cleanup_fclose___attribute__((cleanup(fclosep))) FILE *f = NULL((void*)0); | |||
193 | bool_Bool in_section = false0; | |||
194 | char line[LINE_MAX2048]; | |||
195 | struct stat st; | |||
196 | usec_t t; | |||
197 | int r; | |||
198 | ||||
199 | /* Do not try to re-read the file within single bus operation. */ | |||
200 | if (m && m == c->x11_cache) | |||
201 | return 0; | |||
202 | ||||
203 | /* To suppress multiple call of stat(), store the message to cache here. */ | |||
204 | c->x11_cache = m; | |||
205 | ||||
206 | if (stat("/etc/X11/xorg.conf.d/00-keyboard.conf", &st) < 0) { | |||
207 | if (errno(*__errno_location ()) != ENOENT2) | |||
208 | return -errno(*__errno_location ()); | |||
209 | ||||
210 | c->x11_mtime = USEC_INFINITY((usec_t) -1); | |||
211 | context_free_x11(c); | |||
212 | return 0; | |||
213 | } | |||
214 | ||||
215 | /* If mtime is not changed, then we do not need to re-read */ | |||
216 | t = timespec_load(&st.st_mtim); | |||
217 | if (c->x11_mtime != USEC_INFINITY((usec_t) -1) && t == c->x11_mtime) | |||
218 | return 0; | |||
219 | ||||
220 | c->x11_mtime = t; | |||
221 | context_free_x11(c); | |||
222 | ||||
223 | f = fopen("/etc/X11/xorg.conf.d/00-keyboard.conf", "re"); | |||
224 | if (!f) | |||
225 | return -errno(*__errno_location ()); | |||
226 | ||||
227 | while (fgets(line, sizeof(line), f)) { | |||
228 | char *l; | |||
229 | ||||
230 | char_array_0(line)line[sizeof(line)-1] = 0;; | |||
231 | l = strstrip(line); | |||
232 | ||||
233 | if (IN_SET(l[0], 0, '#')({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended [20 - sizeof((int[]){0, '#'})/sizeof(int)]; switch(l[0]) { case 0: case '#': _found = 1; break; default: break; } _found; })) | |||
234 | continue; | |||
235 | ||||
236 | if (in_section && first_word(l, "Option")) { | |||
237 | _cleanup_strv_free___attribute__((cleanup(strv_freep))) char **a = NULL((void*)0); | |||
238 | ||||
239 | r = strv_split_extract(&a, l, WHITESPACE" \t\n\r", EXTRACT_QUOTES); | |||
240 | if (r < 0) | |||
241 | return r; | |||
242 | ||||
243 | if (strv_length(a) == 3) { | |||
244 | char **p = NULL((void*)0); | |||
245 | ||||
246 | if (streq(a[1], "XkbLayout")(strcmp((a[1]),("XkbLayout")) == 0)) | |||
247 | p = &c->x11_layout; | |||
248 | else if (streq(a[1], "XkbModel")(strcmp((a[1]),("XkbModel")) == 0)) | |||
249 | p = &c->x11_model; | |||
250 | else if (streq(a[1], "XkbVariant")(strcmp((a[1]),("XkbVariant")) == 0)) | |||
251 | p = &c->x11_variant; | |||
252 | else if (streq(a[1], "XkbOptions")(strcmp((a[1]),("XkbOptions")) == 0)) | |||
253 | p = &c->x11_options; | |||
254 | ||||
255 | if (p) { | |||
256 | free_and_replace(*p, a[2])({ free(*p); (*p) = (a[2]); (a[2]) = ((void*)0); 0; }); | |||
257 | } | |||
258 | } | |||
259 | ||||
260 | } else if (!in_section && first_word(l, "Section")) { | |||
261 | _cleanup_strv_free___attribute__((cleanup(strv_freep))) char **a = NULL((void*)0); | |||
262 | ||||
263 | r = strv_split_extract(&a, l, WHITESPACE" \t\n\r", EXTRACT_QUOTES); | |||
264 | if (r < 0) | |||
265 | return -ENOMEM12; | |||
266 | ||||
267 | if (strv_length(a) == 2 && streq(a[1], "InputClass")(strcmp((a[1]),("InputClass")) == 0)) | |||
268 | in_section = true1; | |||
269 | ||||
270 | } else if (in_section && first_word(l, "EndSection")) | |||
271 | in_section = false0; | |||
272 | } | |||
273 | ||||
274 | return 0; | |||
275 | } | |||
276 | ||||
277 | int locale_write_data(Context *c, char ***settings) { | |||
278 | _cleanup_strv_free___attribute__((cleanup(strv_freep))) char **l = NULL((void*)0); | |||
279 | struct stat st; | |||
280 | int r, p; | |||
281 | ||||
282 | /* Set values will be returned as strv in *settings on success. */ | |||
283 | ||||
284 | for (p = 0; p < _VARIABLE_LC_MAX; p++) { | |||
285 | _cleanup_free___attribute__((cleanup(freep))) char *t = NULL((void*)0); | |||
286 | char **u; | |||
287 | const char *name; | |||
288 | ||||
289 | name = locale_variable_to_string(p); | |||
290 | assert(name)do { if ((__builtin_expect(!!(!(name)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("name"), "../src/locale/keymap-util.c", 290 , __PRETTY_FUNCTION__); } while (0); | |||
291 | ||||
292 | if (isempty(c->locale[p])) | |||
293 | continue; | |||
294 | ||||
295 | if (asprintf(&t, "%s=%s", name, c->locale[p]) < 0) | |||
296 | return -ENOMEM12; | |||
297 | ||||
298 | u = strv_env_set(l, t); | |||
299 | if (!u) | |||
300 | return -ENOMEM12; | |||
301 | ||||
302 | strv_free_and_replace(l, u)({ strv_free(l); (l) = (u); (u) = ((void*)0); 0; }); | |||
303 | } | |||
304 | ||||
305 | if (strv_isempty(l)) { | |||
306 | if (unlink("/etc/locale.conf") < 0) | |||
307 | return errno(*__errno_location ()) == ENOENT2 ? 0 : -errno(*__errno_location ()); | |||
308 | ||||
309 | c->locale_mtime = USEC_INFINITY((usec_t) -1); | |||
310 | return 0; | |||
311 | } | |||
312 | ||||
313 | r = write_env_file_label("/etc/locale.conf", l); | |||
314 | if (r < 0) | |||
315 | return r; | |||
316 | ||||
317 | *settings = TAKE_PTR(l)({ typeof(l) _ptr_ = (l); (l) = ((void*)0); _ptr_; }); | |||
318 | ||||
319 | if (stat("/etc/locale.conf", &st) >= 0) | |||
320 | c->locale_mtime = timespec_load(&st.st_mtim); | |||
321 | ||||
322 | return 0; | |||
323 | } | |||
324 | ||||
325 | int vconsole_write_data(Context *c) { | |||
326 | _cleanup_strv_free___attribute__((cleanup(strv_freep))) char **l = NULL((void*)0); | |||
327 | struct stat st; | |||
328 | int r; | |||
329 | ||||
330 | r = load_env_file(NULL((void*)0), "/etc/vconsole.conf", NULL((void*)0), &l); | |||
331 | if (r < 0 && r != -ENOENT2) | |||
332 | return r; | |||
333 | ||||
334 | if (isempty(c->vc_keymap)) | |||
335 | l = strv_env_unset(l, "KEYMAP"); | |||
336 | else { | |||
337 | _cleanup_free___attribute__((cleanup(freep))) char *s = NULL((void*)0); | |||
338 | char **u; | |||
339 | ||||
340 | s = strappend("KEYMAP=", c->vc_keymap); | |||
341 | if (!s) | |||
342 | return -ENOMEM12; | |||
343 | ||||
344 | u = strv_env_set(l, s); | |||
345 | if (!u) | |||
346 | return -ENOMEM12; | |||
347 | ||||
348 | strv_free_and_replace(l, u)({ strv_free(l); (l) = (u); (u) = ((void*)0); 0; }); | |||
349 | } | |||
350 | ||||
351 | if (isempty(c->vc_keymap_toggle)) | |||
352 | l = strv_env_unset(l, "KEYMAP_TOGGLE"); | |||
353 | else { | |||
354 | _cleanup_free___attribute__((cleanup(freep))) char *s = NULL((void*)0); | |||
355 | char **u; | |||
356 | ||||
357 | s = strappend("KEYMAP_TOGGLE=", c->vc_keymap_toggle); | |||
358 | if (!s) | |||
359 | return -ENOMEM12; | |||
360 | ||||
361 | u = strv_env_set(l, s); | |||
362 | if (!u) | |||
363 | return -ENOMEM12; | |||
364 | ||||
365 | strv_free_and_replace(l, u)({ strv_free(l); (l) = (u); (u) = ((void*)0); 0; }); | |||
366 | } | |||
367 | ||||
368 | if (strv_isempty(l)) { | |||
369 | if (unlink("/etc/vconsole.conf") < 0) | |||
370 | return errno(*__errno_location ()) == ENOENT2 ? 0 : -errno(*__errno_location ()); | |||
371 | ||||
372 | c->vc_mtime = USEC_INFINITY((usec_t) -1); | |||
373 | return 0; | |||
374 | } | |||
375 | ||||
376 | r = write_env_file_label("/etc/vconsole.conf", l); | |||
377 | if (r < 0) | |||
378 | return r; | |||
379 | ||||
380 | if (stat("/etc/vconsole.conf", &st) >= 0) | |||
381 | c->vc_mtime = timespec_load(&st.st_mtim); | |||
382 | ||||
383 | return 0; | |||
384 | } | |||
385 | ||||
386 | int x11_write_data(Context *c) { | |||
387 | _cleanup_fclose___attribute__((cleanup(fclosep))) FILE *f = NULL((void*)0); | |||
388 | _cleanup_free___attribute__((cleanup(freep))) char *temp_path = NULL((void*)0); | |||
389 | struct stat st; | |||
390 | int r; | |||
391 | ||||
392 | if (isempty(c->x11_layout) && | |||
393 | isempty(c->x11_model) && | |||
394 | isempty(c->x11_variant) && | |||
395 | isempty(c->x11_options)) { | |||
396 | ||||
397 | if (unlink("/etc/X11/xorg.conf.d/00-keyboard.conf") < 0) | |||
398 | return errno(*__errno_location ()) == ENOENT2 ? 0 : -errno(*__errno_location ()); | |||
399 | ||||
400 | c->vc_mtime = USEC_INFINITY((usec_t) -1); | |||
401 | return 0; | |||
402 | } | |||
403 | ||||
404 | mkdir_p_label("/etc/X11/xorg.conf.d", 0755); | |||
405 | ||||
406 | r = fopen_temporary("/etc/X11/xorg.conf.d/00-keyboard.conf", &f, &temp_path); | |||
407 | if (r < 0) | |||
408 | return r; | |||
409 | ||||
410 | (void) __fsetlocking(f, FSETLOCKING_BYCALLERFSETLOCKING_BYCALLER); | |||
411 | (void) fchmod(fileno(f), 0644); | |||
412 | ||||
413 | fputs("# Written by systemd-localed(8), read by systemd-localed and Xorg. It's\n" | |||
414 | "# probably wise not to edit this file manually. Use localectl(1) to\n" | |||
415 | "# instruct systemd-localed to update it.\n" | |||
416 | "Section \"InputClass\"\n" | |||
417 | " Identifier \"system-keyboard\"\n" | |||
418 | " MatchIsKeyboard \"on\"\n", f); | |||
419 | ||||
420 | if (!isempty(c->x11_layout)) | |||
421 | fprintf(f, " Option \"XkbLayout\" \"%s\"\n", c->x11_layout); | |||
422 | ||||
423 | if (!isempty(c->x11_model)) | |||
424 | fprintf(f, " Option \"XkbModel\" \"%s\"\n", c->x11_model); | |||
425 | ||||
426 | if (!isempty(c->x11_variant)) | |||
427 | fprintf(f, " Option \"XkbVariant\" \"%s\"\n", c->x11_variant); | |||
428 | ||||
429 | if (!isempty(c->x11_options)) | |||
430 | fprintf(f, " Option \"XkbOptions\" \"%s\"\n", c->x11_options); | |||
431 | ||||
432 | fputs("EndSection\n", f); | |||
433 | ||||
434 | r = fflush_sync_and_check(f); | |||
435 | if (r < 0) | |||
436 | goto fail; | |||
437 | ||||
438 | if (rename(temp_path, "/etc/X11/xorg.conf.d/00-keyboard.conf") < 0) { | |||
439 | r = -errno(*__errno_location ()); | |||
440 | goto fail; | |||
441 | } | |||
442 | ||||
443 | if (stat("/etc/X11/xorg.conf.d/00-keyboard.conf", &st) >= 0) | |||
444 | c->x11_mtime = timespec_load(&st.st_mtim); | |||
445 | ||||
446 | return 0; | |||
447 | ||||
448 | fail: | |||
449 | if (temp_path) | |||
450 | (void) unlink(temp_path); | |||
451 | ||||
452 | return r; | |||
453 | } | |||
454 | ||||
455 | static int read_next_mapping(const char* filename, | |||
456 | unsigned min_fields, unsigned max_fields, | |||
457 | FILE *f, unsigned *n, char ***a) { | |||
458 | assert(f)do { if ((__builtin_expect(!!(!(f)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("f"), "../src/locale/keymap-util.c", 458 , __PRETTY_FUNCTION__); } while (0); | |||
459 | assert(n)do { if ((__builtin_expect(!!(!(n)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("n"), "../src/locale/keymap-util.c", 459 , __PRETTY_FUNCTION__); } while (0); | |||
460 | assert(a)do { if ((__builtin_expect(!!(!(a)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("a"), "../src/locale/keymap-util.c", 460 , __PRETTY_FUNCTION__); } while (0); | |||
461 | ||||
462 | for (;;) { | |||
463 | char line[LINE_MAX2048]; | |||
464 | char *l, **b; | |||
465 | int r; | |||
466 | size_t length; | |||
467 | ||||
468 | errno(*__errno_location ()) = 0; | |||
469 | if (!fgets(line, sizeof(line), f)) { | |||
470 | ||||
471 | if (ferror(f)) | |||
472 | return errno(*__errno_location ()) > 0 ? -errno(*__errno_location ()) : -EIO5; | |||
473 | ||||
474 | return 0; | |||
475 | } | |||
476 | ||||
477 | (*n)++; | |||
478 | ||||
479 | l = strstrip(line); | |||
480 | if (IN_SET(l[0], 0, '#')({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended [20 - sizeof((int[]){0, '#'})/sizeof(int)]; switch(l[0]) { case 0: case '#': _found = 1; break; default: break; } _found; })) | |||
481 | continue; | |||
482 | ||||
483 | r = strv_split_extract(&b, l, WHITESPACE" \t\n\r", EXTRACT_QUOTES); | |||
484 | if (r < 0) | |||
485 | return r; | |||
486 | ||||
487 | length = strv_length(b); | |||
488 | if (length < min_fields || length > max_fields) { | |||
489 | log_error("Invalid line %s:%u, ignoring.", filename, *n)({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/locale/keymap-util.c", 489, __func__, "Invalid line %s:%u, ignoring." , filename, *n) : -abs(_e); }); | |||
490 | strv_free(b); | |||
491 | continue; | |||
492 | ||||
493 | } | |||
494 | ||||
495 | *a = b; | |||
496 | return 1; | |||
497 | } | |||
498 | } | |||
499 | ||||
500 | int vconsole_convert_to_x11(Context *c) { | |||
501 | const char *map; | |||
502 | int modified = -1; | |||
503 | ||||
504 | map = systemd_kbd_model_map(); | |||
505 | ||||
506 | if (isempty(c->vc_keymap)) { | |||
507 | modified = | |||
508 | !isempty(c->x11_layout) || | |||
509 | !isempty(c->x11_model) || | |||
510 | !isempty(c->x11_variant) || | |||
511 | !isempty(c->x11_options); | |||
512 | ||||
513 | context_free_x11(c); | |||
514 | } else { | |||
515 | _cleanup_fclose___attribute__((cleanup(fclosep))) FILE *f = NULL((void*)0); | |||
516 | unsigned n = 0; | |||
517 | ||||
518 | f = fopen(map, "re"); | |||
519 | if (!f) | |||
520 | return -errno(*__errno_location ()); | |||
521 | ||||
522 | for (;;) { | |||
523 | _cleanup_strv_free___attribute__((cleanup(strv_freep))) char **a = NULL((void*)0); | |||
524 | int r; | |||
525 | ||||
526 | r = read_next_mapping(map, 5, UINT_MAX(2147483647 *2U +1U), f, &n, &a); | |||
527 | if (r < 0) | |||
528 | return r; | |||
529 | if (r == 0) | |||
530 | break; | |||
531 | ||||
532 | if (!streq(c->vc_keymap, a[0])(strcmp((c->vc_keymap),(a[0])) == 0)) | |||
533 | continue; | |||
534 | ||||
535 | if (!streq_ptr(c->x11_layout, strnulldash(a[1])) || | |||
536 | !streq_ptr(c->x11_model, strnulldash(a[2])) || | |||
537 | !streq_ptr(c->x11_variant, strnulldash(a[3])) || | |||
538 | !streq_ptr(c->x11_options, strnulldash(a[4]))) { | |||
539 | ||||
540 | if (free_and_strdup(&c->x11_layout, strnulldash(a[1])) < 0 || | |||
541 | free_and_strdup(&c->x11_model, strnulldash(a[2])) < 0 || | |||
542 | free_and_strdup(&c->x11_variant, strnulldash(a[3])) < 0 || | |||
543 | free_and_strdup(&c->x11_options, strnulldash(a[4])) < 0) | |||
544 | return -ENOMEM12; | |||
545 | ||||
546 | modified = true1; | |||
547 | } | |||
548 | ||||
549 | break; | |||
550 | } | |||
551 | } | |||
552 | ||||
553 | if (modified > 0) | |||
554 | log_info("Changing X11 keyboard layout to '%s' model '%s' variant '%s' options '%s'",({ int _level = (((6))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/locale/keymap-util.c", 558, __func__, "Changing X11 keyboard layout to '%s' model '%s' variant '%s' options '%s'" , strempty(c->x11_layout), strempty(c->x11_model), strempty (c->x11_variant), strempty(c->x11_options)) : -abs(_e); }) | |||
555 | strempty(c->x11_layout),({ int _level = (((6))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/locale/keymap-util.c", 558, __func__, "Changing X11 keyboard layout to '%s' model '%s' variant '%s' options '%s'" , strempty(c->x11_layout), strempty(c->x11_model), strempty (c->x11_variant), strempty(c->x11_options)) : -abs(_e); }) | |||
556 | strempty(c->x11_model),({ int _level = (((6))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/locale/keymap-util.c", 558, __func__, "Changing X11 keyboard layout to '%s' model '%s' variant '%s' options '%s'" , strempty(c->x11_layout), strempty(c->x11_model), strempty (c->x11_variant), strempty(c->x11_options)) : -abs(_e); }) | |||
557 | strempty(c->x11_variant),({ int _level = (((6))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/locale/keymap-util.c", 558, __func__, "Changing X11 keyboard layout to '%s' model '%s' variant '%s' options '%s'" , strempty(c->x11_layout), strempty(c->x11_model), strempty (c->x11_variant), strempty(c->x11_options)) : -abs(_e); }) | |||
558 | strempty(c->x11_options))({ int _level = (((6))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/locale/keymap-util.c", 558, __func__, "Changing X11 keyboard layout to '%s' model '%s' variant '%s' options '%s'" , strempty(c->x11_layout), strempty(c->x11_model), strempty (c->x11_variant), strempty(c->x11_options)) : -abs(_e); }); | |||
559 | else if (modified < 0) | |||
560 | log_notice("X11 keyboard layout was not modified: no conversion found for \"%s\".",({ int _level = (((5))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/locale/keymap-util.c", 561, __func__, "X11 keyboard layout was not modified: no conversion found for \"%s\"." , c->vc_keymap) : -abs(_e); }) | |||
561 | c->vc_keymap)({ int _level = (((5))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/locale/keymap-util.c", 561, __func__, "X11 keyboard layout was not modified: no conversion found for \"%s\"." , c->vc_keymap) : -abs(_e); }); | |||
562 | else | |||
563 | log_debug("X11 keyboard layout did not need to be modified.")({ int _level = (((7))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/locale/keymap-util.c", 563, __func__, "X11 keyboard layout did not need to be modified." ) : -abs(_e); }); | |||
564 | ||||
565 | return modified > 0; | |||
566 | } | |||
567 | ||||
568 | int find_converted_keymap(const char *x11_layout, const char *x11_variant, char **new_keymap) { | |||
569 | const char *dir; | |||
570 | _cleanup_free___attribute__((cleanup(freep))) char *n; | |||
571 | ||||
572 | if (x11_variant) | |||
573 | n = strjoin(x11_layout, "-", x11_variant)strjoin_real((x11_layout), "-", x11_variant, ((void*)0)); | |||
574 | else | |||
575 | n = strdup(x11_layout); | |||
576 | if (!n) | |||
577 | return -ENOMEM12; | |||
578 | ||||
579 | NULSTR_FOREACH(dir, KBD_KEYMAP_DIRS)for ((dir) = ("/usr/share/keymaps/\0" "/usr/share/kbd/keymaps/\0" "/usr/lib/kbd/keymaps/\0"); (dir) && *(dir); (dir) = strchr((dir), 0)+1) { | |||
580 | _cleanup_free___attribute__((cleanup(freep))) char *p = NULL((void*)0), *pz = NULL((void*)0); | |||
581 | bool_Bool uncompressed; | |||
582 | ||||
583 | p = strjoin(dir, "xkb/", n, ".map")strjoin_real((dir), "xkb/", n, ".map", ((void*)0)); | |||
584 | pz = strjoin(dir, "xkb/", n, ".map.gz")strjoin_real((dir), "xkb/", n, ".map.gz", ((void*)0)); | |||
585 | if (!p || !pz) | |||
586 | return -ENOMEM12; | |||
587 | ||||
588 | uncompressed = access(p, F_OK0) == 0; | |||
589 | if (uncompressed || access(pz, F_OK0) == 0) { | |||
590 | log_debug("Found converted keymap %s at %s",({ int _level = (((7))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/locale/keymap-util.c", 591, __func__, "Found converted keymap %s at %s" , n, uncompressed ? p : pz) : -abs(_e); }) | |||
591 | n, uncompressed ? p : pz)({ int _level = (((7))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/locale/keymap-util.c", 591, __func__, "Found converted keymap %s at %s" , n, uncompressed ? p : pz) : -abs(_e); }); | |||
592 | ||||
593 | *new_keymap = TAKE_PTR(n)({ typeof(n) _ptr_ = (n); (n) = ((void*)0); _ptr_; }); | |||
594 | return 1; | |||
595 | } | |||
596 | } | |||
597 | ||||
598 | return 0; | |||
599 | } | |||
600 | ||||
601 | int find_legacy_keymap(Context *c, char **ret) { | |||
602 | const char *map; | |||
603 | _cleanup_fclose___attribute__((cleanup(fclosep))) FILE *f = NULL((void*)0); | |||
604 | _cleanup_free___attribute__((cleanup(freep))) char *new_keymap = NULL((void*)0); | |||
605 | unsigned n = 0; | |||
606 | unsigned best_matching = 0; | |||
607 | int r; | |||
608 | ||||
609 | assert(!isempty(c->x11_layout))do { if ((__builtin_expect(!!(!(!isempty(c->x11_layout))), 0))) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("!isempty(c->x11_layout)" ), "../src/locale/keymap-util.c", 609, __PRETTY_FUNCTION__); } while (0); | |||
610 | ||||
611 | map = systemd_kbd_model_map(); | |||
612 | ||||
613 | f = fopen(map, "re"); | |||
614 | if (!f) | |||
615 | return -errno(*__errno_location ()); | |||
616 | ||||
617 | for (;;) { | |||
618 | _cleanup_strv_free___attribute__((cleanup(strv_freep))) char **a = NULL((void*)0); | |||
619 | unsigned matching = 0; | |||
620 | ||||
621 | r = read_next_mapping(map, 5, UINT_MAX(2147483647 *2U +1U), f, &n, &a); | |||
622 | if (r < 0) | |||
623 | return r; | |||
624 | if (r == 0) | |||
625 | break; | |||
626 | ||||
627 | /* Determine how well matching this entry is */ | |||
628 | if (streq(c->x11_layout, a[1])(strcmp((c->x11_layout),(a[1])) == 0)) | |||
| ||||
629 | /* If we got an exact match, this is best */ | |||
630 | matching = 10; | |||
631 | else { | |||
632 | /* We have multiple X layouts, look for an | |||
633 | * entry that matches our key with everything | |||
634 | * but the first layout stripped off. */ | |||
635 | if (startswith_comma(c->x11_layout, a[1])) | |||
636 | matching = 5; | |||
637 | else { | |||
638 | char *x; | |||
639 | ||||
640 | /* If that didn't work, strip off the | |||
641 | * other layouts from the entry, too */ | |||
642 | x = strndupa(a[1], strcspn(a[1], ","))(__extension__ ({ const char *__old = (a[1]); size_t __len = strnlen (__old, (strcspn(a[1], ","))); char *__new = (char *) __builtin_alloca (__len + 1); __new[__len] = '\0'; (char *) memcpy (__new, __old , __len); })); | |||
643 | if (startswith_comma(c->x11_layout, x)) | |||
644 | matching = 1; | |||
645 | } | |||
646 | } | |||
647 | ||||
648 | if (matching > 0) { | |||
649 | if (isempty(c->x11_model) || streq_ptr(c->x11_model, a[2])) { | |||
650 | matching++; | |||
651 | ||||
652 | if (streq_ptr(c->x11_variant, a[3])) { | |||
653 | matching++; | |||
654 | ||||
655 | if (streq_ptr(c->x11_options, a[4])) | |||
656 | matching++; | |||
657 | } | |||
658 | } | |||
659 | } | |||
660 | ||||
661 | /* The best matching entry so far, then let's save that */ | |||
662 | if (matching >= MAX(best_matching, 1u)__extension__ ({ const typeof((best_matching)) __unique_prefix_A2 = ((best_matching)); const typeof((1u)) __unique_prefix_B3 = ((1u)); __unique_prefix_A2 > __unique_prefix_B3 ? __unique_prefix_A2 : __unique_prefix_B3; })) { | |||
663 | log_debug("Found legacy keymap %s with score %u",({ int _level = (((7))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/locale/keymap-util.c", 664, __func__, "Found legacy keymap %s with score %u" , a[0], matching) : -abs(_e); }) | |||
664 | a[0], matching)({ int _level = (((7))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/locale/keymap-util.c", 664, __func__, "Found legacy keymap %s with score %u" , a[0], matching) : -abs(_e); }); | |||
665 | ||||
666 | if (matching > best_matching) { | |||
667 | best_matching = matching; | |||
668 | ||||
669 | r = free_and_strdup(&new_keymap, a[0]); | |||
670 | if (r < 0) | |||
671 | return r; | |||
672 | } | |||
673 | } | |||
674 | } | |||
675 | ||||
676 | if (best_matching < 10 && c->x11_layout) { | |||
677 | /* The best match is only the first part of the X11 | |||
678 | * keymap. Check if we have a converted map which | |||
679 | * matches just the first layout. | |||
680 | */ | |||
681 | char *l, *v = NULL((void*)0), *converted; | |||
682 | ||||
683 | l = strndupa(c->x11_layout, strcspn(c->x11_layout, ","))(__extension__ ({ const char *__old = (c->x11_layout); size_t __len = strnlen (__old, (strcspn(c->x11_layout, ","))); char *__new = (char *) __builtin_alloca (__len + 1); __new[__len] = '\0'; (char *) memcpy (__new, __old, __len); })); | |||
684 | if (c->x11_variant) | |||
685 | v = strndupa(c->x11_variant, strcspn(c->x11_variant, ","))(__extension__ ({ const char *__old = (c->x11_variant); size_t __len = strnlen (__old, (strcspn(c->x11_variant, ","))); char *__new = (char *) __builtin_alloca (__len + 1); __new[__len] = '\0'; (char *) memcpy (__new, __old, __len); })); | |||
686 | r = find_converted_keymap(l, v, &converted); | |||
687 | if (r < 0) | |||
688 | return r; | |||
689 | if (r > 0) | |||
690 | free_and_replace(new_keymap, converted)({ free(new_keymap); (new_keymap) = (converted); (converted) = ((void*)0); 0; }); | |||
691 | } | |||
692 | ||||
693 | *ret = TAKE_PTR(new_keymap)({ typeof(new_keymap) _ptr_ = (new_keymap); (new_keymap) = (( void*)0); _ptr_; }); | |||
694 | return (bool_Bool) *ret; | |||
695 | } | |||
696 | ||||
697 | int find_language_fallback(const char *lang, char **language) { | |||
698 | const char *map; | |||
699 | _cleanup_fclose___attribute__((cleanup(fclosep))) FILE *f = NULL((void*)0); | |||
700 | unsigned n = 0; | |||
701 | ||||
702 | assert(lang)do { if ((__builtin_expect(!!(!(lang)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("lang"), "../src/locale/keymap-util.c", 702 , __PRETTY_FUNCTION__); } while (0); | |||
703 | assert(language)do { if ((__builtin_expect(!!(!(language)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("language"), "../src/locale/keymap-util.c" , 703, __PRETTY_FUNCTION__); } while (0); | |||
704 | ||||
705 | map = systemd_language_fallback_map(); | |||
706 | ||||
707 | f = fopen(map, "re"); | |||
708 | if (!f) | |||
709 | return -errno(*__errno_location ()); | |||
710 | ||||
711 | for (;;) { | |||
712 | _cleanup_strv_free___attribute__((cleanup(strv_freep))) char **a = NULL((void*)0); | |||
713 | int r; | |||
714 | ||||
715 | r = read_next_mapping(map, 2, 2, f, &n, &a); | |||
716 | if (r <= 0) | |||
717 | return r; | |||
718 | ||||
719 | if (streq(lang, a[0])(strcmp((lang),(a[0])) == 0)) { | |||
720 | assert(strv_length(a) == 2)do { if ((__builtin_expect(!!(!(strv_length(a) == 2)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("strv_length(a) == 2"), "../src/locale/keymap-util.c" , 720, __PRETTY_FUNCTION__); } while (0); | |||
721 | *language = TAKE_PTR(a[1])({ typeof(a[1]) _ptr_ = (a[1]); (a[1]) = ((void*)0); _ptr_; } ); | |||
722 | return 1; | |||
723 | } | |||
724 | } | |||
725 | ||||
726 | assert_not_reached("should not be here")do { log_assert_failed_unreachable_realm(LOG_REALM_SYSTEMD, ( "should not be here"), "../src/locale/keymap-util.c", 726, __PRETTY_FUNCTION__ ); } while (0); | |||
727 | } | |||
728 | ||||
729 | int x11_convert_to_vconsole(Context *c) { | |||
730 | bool_Bool modified = false0; | |||
731 | ||||
732 | if (isempty(c->x11_layout)) { | |||
| ||||
733 | modified = | |||
734 | !isempty(c->vc_keymap) || | |||
735 | !isempty(c->vc_keymap_toggle); | |||
736 | ||||
737 | context_free_vconsole(c); | |||
738 | } else { | |||
739 | _cleanup_free___attribute__((cleanup(freep))) char *new_keymap = NULL((void*)0); | |||
740 | int r; | |||
741 | ||||
742 | r = find_converted_keymap(c->x11_layout, c->x11_variant, &new_keymap); | |||
743 | if (r < 0) | |||
744 | return r; | |||
745 | else if (r == 0) { | |||
746 | r = find_legacy_keymap(c, &new_keymap); | |||
747 | if (r < 0) | |||
748 | return r; | |||
749 | } | |||
750 | if (r == 0) | |||
751 | /* We search for layout-variant match first, but then we also look | |||
752 | * for anything which matches just the layout. So it's accurate to say | |||
753 | * that we couldn't find anything which matches the layout. */ | |||
754 | log_notice("No conversion to virtual console map found for \"%s\".",({ int _level = (((5))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/locale/keymap-util.c", 755, __func__, "No conversion to virtual console map found for \"%s\"." , c->x11_layout) : -abs(_e); }) | |||
755 | c->x11_layout)({ int _level = (((5))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/locale/keymap-util.c", 755, __func__, "No conversion to virtual console map found for \"%s\"." , c->x11_layout) : -abs(_e); }); | |||
756 | ||||
757 | if (!streq_ptr(c->vc_keymap, new_keymap)) { | |||
758 | free_and_replace(c->vc_keymap, new_keymap)({ free(c->vc_keymap); (c->vc_keymap) = (new_keymap); ( new_keymap) = ((void*)0); 0; }); | |||
759 | c->vc_keymap_toggle = mfree(c->vc_keymap_toggle); | |||
760 | modified = true1; | |||
761 | } | |||
762 | } | |||
763 | ||||
764 | if (modified) | |||
765 | log_info("Changing virtual console keymap to '%s' toggle '%s'",({ int _level = (((6))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/locale/keymap-util.c", 766, __func__, "Changing virtual console keymap to '%s' toggle '%s'" , strempty(c->vc_keymap), strempty(c->vc_keymap_toggle) ) : -abs(_e); }) | |||
766 | strempty(c->vc_keymap), strempty(c->vc_keymap_toggle))({ int _level = (((6))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/locale/keymap-util.c", 766, __func__, "Changing virtual console keymap to '%s' toggle '%s'" , strempty(c->vc_keymap), strempty(c->vc_keymap_toggle) ) : -abs(_e); }); | |||
767 | else | |||
768 | log_debug("Virtual console keymap was not modified.")({ int _level = (((7))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/locale/keymap-util.c", 768, __func__, "Virtual console keymap was not modified." ) : -abs(_e); }); | |||
769 | ||||
770 | return modified; | |||
771 | } |