Bug Summary

File:build-scan/../src/locale/keymap-util.c
Warning:line 628, column 21
Array access (from variable 'a') results in a null pointer dereference

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name keymap-util.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model static -mframe-pointer=all -relaxed-aliasing -menable-no-infs -menable-no-nans -menable-unsafe-fp-math -fno-signed-zeros -mreassociate -freciprocal-math -fdenormal-fp-math=preserve-sign,preserve-sign -ffp-contract=fast -fno-rounding-math -ffast-math -ffinite-math-only -mconstructor-aliases -munwind-tables -target-cpu x86-64 -tune-cpu generic -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/12.0.0 -include config.h -I test-keymap-util.p -I . -I .. -I src/basic -I ../src/basic -I src/shared -I ../src/shared -I src/systemd -I ../src/systemd -I src/journal -I ../src/journal -I src/journal-remote -I ../src/journal-remote -I src/nspawn -I ../src/nspawn -I src/resolve -I ../src/resolve -I src/timesync -I ../src/timesync -I ../src/time-wait-sync -I src/login -I ../src/login -I src/udev -I ../src/udev -I src/libudev -I ../src/libudev -I src/core -I ../src/core -I ../src/libsystemd/sd-bus -I ../src/libsystemd/sd-device -I ../src/libsystemd/sd-hwdb -I ../src/libsystemd/sd-id128 -I ../src/libsystemd/sd-netlink -I ../src/libsystemd/sd-network -I src/libsystemd-network -I ../src/libsystemd-network -D _FILE_OFFSET_BITS=64 -internal-isystem /usr/local/include -internal-isystem /usr/lib64/clang/12.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -Wwrite-strings -Wno-unused-parameter -Wno-missing-field-initializers -Wno-unused-result -Wno-format-signedness -Wno-error=nonnull -std=gnu99 -fconst-strings -fdebug-compilation-dir /home/mrc0mmand/repos/@redhat-plumbers/systemd-rhel8/build-scan -ferror-limit 19 -fvisibility hidden -stack-protector 2 -fgnuc-version=4.2.1 -fcolor-diagnostics -analyzer-output=html -faddrsig -o /tmp/scan-build-2021-07-16-221226-1465241-1 -x c ../src/locale/keymap-util.c
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
20static 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
28static const char* strnulldash(const char *s) {
29 return isempty(s) || streq(s, "-")(strcmp((s),("-")) == 0) ? NULL((void*)0) : s;
30}
31
32static 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
42static 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
52static 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
59static 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
64static 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
71void context_free(Context *c) {
72 context_free_locale(c);
73 context_free_x11(c);
74 context_free_vconsole(c);
75};
76
77void 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
85int 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
152int 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
191int 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
277int 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
325int 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
386int 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
448fail:
449 if (temp_path)
450 (void) unlink(temp_path);
451
452 return r;
453}
454
455static 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)
;
14
Taking false branch
15
Loop condition is false. Exiting loop
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)
;
16
Taking false branch
17
Loop condition is false. Exiting loop
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)
;
18
Taking false branch
19
Loop condition is false. Exiting loop
461
462 for (;;) {
20
Loop condition is true. Entering loop body
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)) {
21
Assuming the condition is true
22
Taking true branch
470
471 if (ferror(f))
23
Assuming the condition is true
24
Taking true branch
472 return errno(*__errno_location ()) > 0 ? -errno(*__errno_location ()) : -EIO5;
25
Assuming the condition is true
26
'?' condition is true
27
Returning without writing to '*a'
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
500int 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
568int 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
601int 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)
;
7
Taking false branch
8
Loop condition is false. Exiting loop
610
611 map = systemd_kbd_model_map();
612
613 f = fopen(map, "re");
614 if (!f)
9
Assuming 'f' is non-null
10
Taking false branch
615 return -errno(*__errno_location ());
616
617 for (;;) {
11
Loop condition is true. Entering loop body
618 _cleanup_strv_free___attribute__((cleanup(strv_freep))) char **a = NULL((void*)0);
12
'a' initialized to a null pointer value
619 unsigned matching = 0;
620
621 r = read_next_mapping(map, 5, UINT_MAX(2147483647 *2U +1U), f, &n, &a);
13
Calling 'read_next_mapping'
28
Returning from 'read_next_mapping'
622 if (r < 0)
29
Assuming 'r' is >= 0
30
Taking false branch
623 return r;
624 if (r == 0)
31
Assuming 'r' is not equal to 0
32
Taking false branch
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))
33
Array access (from variable 'a') results in a null pointer dereference
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
697int 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
729int x11_convert_to_vconsole(Context *c) {
730 bool_Bool modified = false0;
731
732 if (isempty(c->x11_layout)) {
1
Taking false branch
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)
2
Assuming 'r' is >= 0
3
Taking false branch
744 return r;
745 else if (r == 0) {
4
Assuming 'r' is equal to 0
5
Taking true branch
746 r = find_legacy_keymap(c, &new_keymap);
6
Calling 'find_legacy_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}