mirror of
https://github.com/systemd/systemd-stable.git
synced 2025-01-08 21:17:47 +03:00
Merge pull request #25805 from yuwata/locale-xkb-save-vconsole
locale: also save X11 keyboard settings to /etc/vconsole.conf
This commit is contained in:
commit
deeebc95af
@ -26,6 +26,9 @@
|
||||
#include "tmpfile-util.h"
|
||||
|
||||
static bool startswith_comma(const char *s, const char *prefix) {
|
||||
assert(s);
|
||||
assert(prefix);
|
||||
|
||||
s = startswith(s, prefix);
|
||||
if (!s)
|
||||
return false;
|
||||
@ -53,30 +56,140 @@ static const char* systemd_language_fallback_map(void) {
|
||||
return SYSTEMD_LANGUAGE_FALLBACK_MAP;
|
||||
}
|
||||
|
||||
static void context_free_x11(Context *c) {
|
||||
c->x11_layout = mfree(c->x11_layout);
|
||||
c->x11_options = mfree(c->x11_options);
|
||||
c->x11_model = mfree(c->x11_model);
|
||||
c->x11_variant = mfree(c->x11_variant);
|
||||
static void x11_context_clear(X11Context *xc) {
|
||||
assert(xc);
|
||||
|
||||
xc->layout = mfree(xc->layout);
|
||||
xc->options = mfree(xc->options);
|
||||
xc->model = mfree(xc->model);
|
||||
xc->variant = mfree(xc->variant);
|
||||
}
|
||||
|
||||
static void context_free_vconsole(Context *c) {
|
||||
static bool x11_context_isempty(const X11Context *xc) {
|
||||
assert(xc);
|
||||
|
||||
return
|
||||
isempty(xc->layout) &&
|
||||
isempty(xc->model) &&
|
||||
isempty(xc->variant) &&
|
||||
isempty(xc->options);
|
||||
}
|
||||
|
||||
void x11_context_empty_to_null(X11Context *xc) {
|
||||
assert(xc);
|
||||
|
||||
/* Do not call x11_context_clear() for the passed object. */
|
||||
|
||||
xc->layout = empty_to_null(xc->layout);
|
||||
xc->model = empty_to_null(xc->model);
|
||||
xc->variant = empty_to_null(xc->variant);
|
||||
xc->options = empty_to_null(xc->options);
|
||||
}
|
||||
|
||||
bool x11_context_is_safe(const X11Context *xc) {
|
||||
assert(xc);
|
||||
|
||||
return
|
||||
(!xc->layout || string_is_safe(xc->layout)) &&
|
||||
(!xc->model || string_is_safe(xc->model)) &&
|
||||
(!xc->variant || string_is_safe(xc->variant)) &&
|
||||
(!xc->options || string_is_safe(xc->options));
|
||||
}
|
||||
|
||||
bool x11_context_equal(const X11Context *a, const X11Context *b) {
|
||||
assert(a);
|
||||
assert(b);
|
||||
|
||||
return
|
||||
streq_ptr(a->layout, b->layout) &&
|
||||
streq_ptr(a->model, b->model) &&
|
||||
streq_ptr(a->variant, b->variant) &&
|
||||
streq_ptr(a->options, b->options);
|
||||
}
|
||||
|
||||
int x11_context_copy(X11Context *dest, const X11Context *src) {
|
||||
bool modified;
|
||||
int r;
|
||||
|
||||
assert(dest);
|
||||
|
||||
if (dest == src)
|
||||
return 0;
|
||||
|
||||
if (!src) {
|
||||
modified = !x11_context_isempty(dest);
|
||||
x11_context_clear(dest);
|
||||
return modified;
|
||||
}
|
||||
|
||||
r = free_and_strdup(&dest->layout, src->layout);
|
||||
if (r < 0)
|
||||
return r;
|
||||
modified = r > 0;
|
||||
|
||||
r = free_and_strdup(&dest->model, src->model);
|
||||
if (r < 0)
|
||||
return r;
|
||||
modified = modified || r > 0;
|
||||
|
||||
r = free_and_strdup(&dest->variant, src->variant);
|
||||
if (r < 0)
|
||||
return r;
|
||||
modified = modified || r > 0;
|
||||
|
||||
r = free_and_strdup(&dest->options, src->options);
|
||||
if (r < 0)
|
||||
return r;
|
||||
modified = modified || r > 0;
|
||||
|
||||
return modified;
|
||||
}
|
||||
|
||||
static void context_clear_x11(Context *c) {
|
||||
assert(c);
|
||||
|
||||
x11_context_clear(&c->x11_from_xorg);
|
||||
x11_context_clear(&c->x11_from_vc);
|
||||
}
|
||||
|
||||
static void context_clear_vconsole(Context *c) {
|
||||
assert(c);
|
||||
|
||||
c->vc_keymap = mfree(c->vc_keymap);
|
||||
c->vc_keymap_toggle = mfree(c->vc_keymap_toggle);
|
||||
}
|
||||
|
||||
void context_clear(Context *c) {
|
||||
assert(c);
|
||||
|
||||
locale_context_clear(&c->locale_context);
|
||||
context_free_x11(c);
|
||||
context_free_vconsole(c);
|
||||
context_clear_x11(c);
|
||||
context_clear_vconsole(c);
|
||||
|
||||
sd_bus_message_unref(c->locale_cache);
|
||||
sd_bus_message_unref(c->x11_cache);
|
||||
sd_bus_message_unref(c->vc_cache);
|
||||
c->locale_cache = sd_bus_message_unref(c->locale_cache);
|
||||
c->x11_cache = sd_bus_message_unref(c->x11_cache);
|
||||
c->vc_cache = sd_bus_message_unref(c->vc_cache);
|
||||
|
||||
bus_verify_polkit_async_registry_free(c->polkit_registry);
|
||||
c->polkit_registry = bus_verify_polkit_async_registry_free(c->polkit_registry);
|
||||
};
|
||||
|
||||
static X11Context *context_get_x11_context(Context *c) {
|
||||
assert(c);
|
||||
|
||||
if (!x11_context_isempty(&c->x11_from_vc))
|
||||
return &c->x11_from_vc;
|
||||
|
||||
if (!x11_context_isempty(&c->x11_from_xorg))
|
||||
return &c->x11_from_xorg;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
X11Context *context_get_x11_context_safe(Context *c) {
|
||||
assert(c);
|
||||
return context_get_x11_context(c) ?: &c->x11_from_vc;
|
||||
}
|
||||
|
||||
int locale_read_data(Context *c, sd_bus_message *m) {
|
||||
assert(c);
|
||||
|
||||
@ -96,6 +209,8 @@ int vconsole_read_data(Context *c, sd_bus_message *m) {
|
||||
_cleanup_close_ int fd = -EBADF;
|
||||
struct stat st;
|
||||
|
||||
assert(c);
|
||||
|
||||
/* Do not try to re-read the file within single bus operation. */
|
||||
if (m) {
|
||||
if (m == c->vc_cache)
|
||||
@ -108,7 +223,7 @@ int vconsole_read_data(Context *c, sd_bus_message *m) {
|
||||
fd = RET_NERRNO(open("/etc/vconsole.conf", O_CLOEXEC | O_PATH));
|
||||
if (fd == -ENOENT) {
|
||||
c->vc_stat = (struct stat) {};
|
||||
context_free_vconsole(c);
|
||||
context_clear_vconsole(c);
|
||||
return 0;
|
||||
}
|
||||
if (fd < 0)
|
||||
@ -122,11 +237,16 @@ int vconsole_read_data(Context *c, sd_bus_message *m) {
|
||||
return 0;
|
||||
|
||||
c->vc_stat = st;
|
||||
context_free_vconsole(c);
|
||||
context_clear_vconsole(c);
|
||||
x11_context_clear(&c->x11_from_vc);
|
||||
|
||||
return parse_env_file_fd(fd, "/etc/vconsole.conf",
|
||||
"KEYMAP", &c->vc_keymap,
|
||||
"KEYMAP_TOGGLE", &c->vc_keymap_toggle);
|
||||
"KEYMAP_TOGGLE", &c->vc_keymap_toggle,
|
||||
"XKB_LAYOUT", &c->x11_from_vc.layout,
|
||||
"XKB_MODEL", &c->x11_from_vc.model,
|
||||
"XKB_VARIANT", &c->x11_from_vc.variant,
|
||||
"XKB_OPTIONS", &c->x11_from_vc.options);
|
||||
}
|
||||
|
||||
int x11_read_data(Context *c, sd_bus_message *m) {
|
||||
@ -136,6 +256,17 @@ int x11_read_data(Context *c, sd_bus_message *m) {
|
||||
struct stat st;
|
||||
int r;
|
||||
|
||||
assert(c);
|
||||
|
||||
r = vconsole_read_data(c, m);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (!x11_context_isempty(&c->x11_from_vc)) {
|
||||
log_debug("XKB settings loaded from vconsole.conf, not reading xorg.conf.d/00-keyboard.conf.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Do not try to re-read the file within single bus operation. */
|
||||
if (m) {
|
||||
if (m == c->x11_cache)
|
||||
@ -148,7 +279,7 @@ int x11_read_data(Context *c, sd_bus_message *m) {
|
||||
fd = RET_NERRNO(open("/etc/X11/xorg.conf.d/00-keyboard.conf", O_CLOEXEC | O_PATH));
|
||||
if (fd == -ENOENT) {
|
||||
c->x11_stat = (struct stat) {};
|
||||
context_free_x11(c);
|
||||
context_clear_x11(c);
|
||||
return 0;
|
||||
}
|
||||
if (fd < 0)
|
||||
@ -162,7 +293,7 @@ int x11_read_data(Context *c, sd_bus_message *m) {
|
||||
return 0;
|
||||
|
||||
c->x11_stat = st;
|
||||
context_free_x11(c);
|
||||
x11_context_clear(&c->x11_from_xorg);
|
||||
|
||||
fd_ro = fd_reopen(fd, O_CLOEXEC | O_RDONLY);
|
||||
if (fd_ro < 0)
|
||||
@ -199,13 +330,13 @@ int x11_read_data(Context *c, sd_bus_message *m) {
|
||||
char **p = NULL;
|
||||
|
||||
if (streq(a[1], "XkbLayout"))
|
||||
p = &c->x11_layout;
|
||||
p = &c->x11_from_xorg.layout;
|
||||
else if (streq(a[1], "XkbModel"))
|
||||
p = &c->x11_model;
|
||||
p = &c->x11_from_xorg.model;
|
||||
else if (streq(a[1], "XkbVariant"))
|
||||
p = &c->x11_variant;
|
||||
p = &c->x11_from_xorg.variant;
|
||||
else if (streq(a[1], "XkbOptions"))
|
||||
p = &c->x11_options;
|
||||
p = &c->x11_from_xorg.options;
|
||||
|
||||
if (p)
|
||||
free_and_replace(*p, a[2]);
|
||||
@ -225,13 +356,26 @@ int x11_read_data(Context *c, sd_bus_message *m) {
|
||||
in_section = false;
|
||||
}
|
||||
|
||||
if (!x11_context_isempty(&c->x11_from_xorg))
|
||||
log_debug("XKB settings loaded from xorg.conf.d/00-keyboard.conf.");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int vconsole_write_data(Context *c) {
|
||||
_cleanup_strv_free_ char **l = NULL;
|
||||
const X11Context *xc;
|
||||
int r;
|
||||
|
||||
assert(c);
|
||||
|
||||
xc = context_get_x11_context(c);
|
||||
|
||||
/* If the X11 context is from xorg.conf, then sync one from vconsole.conf with it. */
|
||||
r = x11_context_copy(&c->x11_from_vc, xc);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = load_env_file(NULL, "/etc/vconsole.conf", &l);
|
||||
if (r < 0 && r != -ENOENT)
|
||||
return r;
|
||||
@ -244,6 +388,22 @@ int vconsole_write_data(Context *c) {
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = strv_env_assign(&l, "XKB_LAYOUT", xc ? empty_to_null(xc->layout) : NULL);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = strv_env_assign(&l, "XKB_MODEL", xc ? empty_to_null(xc->model) : NULL);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = strv_env_assign(&l, "XKB_VARIANT", xc ? empty_to_null(xc->variant) : NULL);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = strv_env_assign(&l, "XKB_OPTIONS", xc ? empty_to_null(xc->options) : NULL);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (strv_isempty(l)) {
|
||||
if (unlink("/etc/vconsole.conf") < 0)
|
||||
return errno == ENOENT ? 0 : -errno;
|
||||
@ -265,13 +425,13 @@ int vconsole_write_data(Context *c) {
|
||||
int x11_write_data(Context *c) {
|
||||
_cleanup_fclose_ FILE *f = NULL;
|
||||
_cleanup_(unlink_and_freep) char *temp_path = NULL;
|
||||
const X11Context *xc;
|
||||
int r;
|
||||
|
||||
if (isempty(c->x11_layout) &&
|
||||
isempty(c->x11_model) &&
|
||||
isempty(c->x11_variant) &&
|
||||
isempty(c->x11_options)) {
|
||||
assert(c);
|
||||
|
||||
xc = context_get_x11_context(c);
|
||||
if (!xc) {
|
||||
if (unlink("/etc/X11/xorg.conf.d/00-keyboard.conf") < 0)
|
||||
return errno == ENOENT ? 0 : -errno;
|
||||
|
||||
@ -293,17 +453,17 @@ int x11_write_data(Context *c) {
|
||||
" Identifier \"system-keyboard\"\n"
|
||||
" MatchIsKeyboard \"on\"\n", f);
|
||||
|
||||
if (!isempty(c->x11_layout))
|
||||
fprintf(f, " Option \"XkbLayout\" \"%s\"\n", c->x11_layout);
|
||||
if (!isempty(xc->layout))
|
||||
fprintf(f, " Option \"XkbLayout\" \"%s\"\n", xc->layout);
|
||||
|
||||
if (!isempty(c->x11_model))
|
||||
fprintf(f, " Option \"XkbModel\" \"%s\"\n", c->x11_model);
|
||||
if (!isempty(xc->model))
|
||||
fprintf(f, " Option \"XkbModel\" \"%s\"\n", xc->model);
|
||||
|
||||
if (!isempty(c->x11_variant))
|
||||
fprintf(f, " Option \"XkbVariant\" \"%s\"\n", c->x11_variant);
|
||||
if (!isempty(xc->variant))
|
||||
fprintf(f, " Option \"XkbVariant\" \"%s\"\n", xc->variant);
|
||||
|
||||
if (!isempty(c->x11_options))
|
||||
fprintf(f, " Option \"XkbOptions\" \"%s\"\n", c->x11_options);
|
||||
if (!isempty(xc->options))
|
||||
fprintf(f, " Option \"XkbOptions\" \"%s\"\n", xc->options);
|
||||
|
||||
fputs("EndSection\n", f);
|
||||
|
||||
@ -320,17 +480,23 @@ int x11_write_data(Context *c) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int read_next_mapping(const char* filename,
|
||||
unsigned min_fields, unsigned max_fields,
|
||||
FILE *f, unsigned *n, char ***a) {
|
||||
static int read_next_mapping(
|
||||
const char *filename,
|
||||
unsigned min_fields,
|
||||
unsigned max_fields,
|
||||
FILE *f,
|
||||
unsigned *n,
|
||||
char ***ret) {
|
||||
|
||||
assert(f);
|
||||
assert(n);
|
||||
assert(a);
|
||||
assert(ret);
|
||||
|
||||
for (;;) {
|
||||
_cleanup_strv_free_ char **b = NULL;
|
||||
_cleanup_free_ char *line = NULL;
|
||||
size_t length;
|
||||
char *l, **b;
|
||||
const char *l;
|
||||
int r;
|
||||
|
||||
r = read_line(f, LONG_LINE_MAX, &line);
|
||||
@ -351,44 +517,45 @@ static int read_next_mapping(const char* filename,
|
||||
|
||||
length = strv_length(b);
|
||||
if (length < min_fields || length > max_fields) {
|
||||
log_error("Invalid line %s:%u, ignoring.", filename, *n);
|
||||
strv_free(b);
|
||||
log_warning("Invalid line %s:%u, ignoring.", strna(filename), *n);
|
||||
continue;
|
||||
|
||||
}
|
||||
|
||||
*a = b;
|
||||
*ret = TAKE_PTR(b);
|
||||
return 1;
|
||||
}
|
||||
|
||||
*ret = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int vconsole_convert_to_x11(Context *c) {
|
||||
const char *map;
|
||||
int modified = -1;
|
||||
int r, modified = -1;
|
||||
X11Context *xc;
|
||||
|
||||
map = systemd_kbd_model_map();
|
||||
assert(c);
|
||||
|
||||
/* If Context.x11_from_vc is empty, then here we update Context.x11_from_xorg, as the caller may
|
||||
* already have been called context_get_x11_context() or _safe(), and otherwise the caller's
|
||||
* X11Context may be outdated. The updated context will be copied to Context.x11_from_vc in
|
||||
* vconsole_write_data() if necessary. */
|
||||
xc = context_get_x11_context_safe(c);
|
||||
|
||||
if (isempty(c->vc_keymap)) {
|
||||
modified =
|
||||
!isempty(c->x11_layout) ||
|
||||
!isempty(c->x11_model) ||
|
||||
!isempty(c->x11_variant) ||
|
||||
!isempty(c->x11_options);
|
||||
|
||||
context_free_x11(c);
|
||||
modified = !x11_context_isempty(xc);
|
||||
context_clear_x11(c);
|
||||
} else {
|
||||
_cleanup_fclose_ FILE *f = NULL;
|
||||
unsigned n = 0;
|
||||
const char *map;
|
||||
|
||||
map = systemd_kbd_model_map();
|
||||
f = fopen(map, "re");
|
||||
if (!f)
|
||||
return -errno;
|
||||
|
||||
for (;;) {
|
||||
for (unsigned n = 0;;) {
|
||||
_cleanup_strv_free_ char **a = NULL;
|
||||
int r;
|
||||
|
||||
r = read_next_mapping(map, 5, UINT_MAX, f, &n, &a);
|
||||
if (r < 0)
|
||||
@ -399,19 +566,16 @@ int vconsole_convert_to_x11(Context *c) {
|
||||
if (!streq(c->vc_keymap, a[0]))
|
||||
continue;
|
||||
|
||||
if (!streq_ptr(c->x11_layout, empty_or_dash_to_null(a[1])) ||
|
||||
!streq_ptr(c->x11_model, empty_or_dash_to_null(a[2])) ||
|
||||
!streq_ptr(c->x11_variant, empty_or_dash_to_null(a[3])) ||
|
||||
!streq_ptr(c->x11_options, empty_or_dash_to_null(a[4]))) {
|
||||
|
||||
if (free_and_strdup(&c->x11_layout, empty_or_dash_to_null(a[1])) < 0 ||
|
||||
free_and_strdup(&c->x11_model, empty_or_dash_to_null(a[2])) < 0 ||
|
||||
free_and_strdup(&c->x11_variant, empty_or_dash_to_null(a[3])) < 0 ||
|
||||
free_and_strdup(&c->x11_options, empty_or_dash_to_null(a[4])) < 0)
|
||||
return -ENOMEM;
|
||||
|
||||
modified = true;
|
||||
}
|
||||
r = x11_context_copy(xc,
|
||||
&(X11Context) {
|
||||
.layout = empty_or_dash_to_null(a[1]),
|
||||
.model = empty_or_dash_to_null(a[2]),
|
||||
.variant = empty_or_dash_to_null(a[3]),
|
||||
.options = empty_or_dash_to_null(a[4]),
|
||||
});
|
||||
if (r < 0)
|
||||
return r;
|
||||
modified = r > 0;
|
||||
|
||||
break;
|
||||
}
|
||||
@ -419,10 +583,10 @@ int vconsole_convert_to_x11(Context *c) {
|
||||
|
||||
if (modified > 0)
|
||||
log_info("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));
|
||||
strempty(xc->layout),
|
||||
strempty(xc->model),
|
||||
strempty(xc->variant),
|
||||
strempty(xc->options));
|
||||
else if (modified < 0)
|
||||
log_notice("X11 keyboard layout was not modified: no conversion found for \"%s\".",
|
||||
c->vc_keymap);
|
||||
@ -432,13 +596,17 @@ int vconsole_convert_to_x11(Context *c) {
|
||||
return modified > 0;
|
||||
}
|
||||
|
||||
int find_converted_keymap(const char *x11_layout, const char *x11_variant, char **new_keymap) {
|
||||
int find_converted_keymap(const X11Context *xc, char **ret) {
|
||||
_cleanup_free_ char *n = NULL;
|
||||
|
||||
if (x11_variant)
|
||||
n = strjoin(x11_layout, "-", x11_variant);
|
||||
assert(xc);
|
||||
assert(!isempty(xc->layout));
|
||||
assert(ret);
|
||||
|
||||
if (xc->variant)
|
||||
n = strjoin(xc->layout, "-", xc->variant);
|
||||
else
|
||||
n = strdup(x11_layout);
|
||||
n = strdup(xc->layout);
|
||||
if (!n)
|
||||
return -ENOMEM;
|
||||
|
||||
@ -453,34 +621,32 @@ int find_converted_keymap(const char *x11_layout, const char *x11_variant, char
|
||||
|
||||
uncompressed = access(p, F_OK) == 0;
|
||||
if (uncompressed || access(pz, F_OK) == 0) {
|
||||
log_debug("Found converted keymap %s at %s",
|
||||
n, uncompressed ? p : pz);
|
||||
|
||||
*new_keymap = TAKE_PTR(n);
|
||||
log_debug("Found converted keymap %s at %s", n, uncompressed ? p : pz);
|
||||
*ret = TAKE_PTR(n);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
*ret = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int find_legacy_keymap(Context *c, char **ret) {
|
||||
int find_legacy_keymap(const X11Context *xc, char **ret) {
|
||||
const char *map;
|
||||
_cleanup_fclose_ FILE *f = NULL;
|
||||
_cleanup_free_ char *new_keymap = NULL;
|
||||
unsigned n = 0;
|
||||
unsigned best_matching = 0;
|
||||
int r;
|
||||
|
||||
assert(!isempty(c->x11_layout));
|
||||
assert(xc);
|
||||
assert(!isempty(xc->layout));
|
||||
|
||||
map = systemd_kbd_model_map();
|
||||
|
||||
f = fopen(map, "re");
|
||||
if (!f)
|
||||
return -errno;
|
||||
|
||||
for (;;) {
|
||||
for (unsigned n = 0;;) {
|
||||
_cleanup_strv_free_ char **a = NULL;
|
||||
unsigned matching = 0;
|
||||
|
||||
@ -491,16 +657,16 @@ int find_legacy_keymap(Context *c, char **ret) {
|
||||
break;
|
||||
|
||||
/* Determine how well matching this entry is */
|
||||
if (streq(c->x11_layout, a[1]))
|
||||
/* If we got an exact match, this is best */
|
||||
if (streq(xc->layout, a[1]))
|
||||
/* If we got an exact match, this is the best */
|
||||
matching = 10;
|
||||
else {
|
||||
/* We have multiple X layouts, look for an
|
||||
* entry that matches our key with everything
|
||||
* but the first layout stripped off. */
|
||||
if (startswith_comma(c->x11_layout, a[1]))
|
||||
if (startswith_comma(xc->layout, a[1]))
|
||||
matching = 5;
|
||||
else {
|
||||
else {
|
||||
_cleanup_free_ char *x = NULL;
|
||||
|
||||
/* If that didn't work, strip off the
|
||||
@ -508,19 +674,19 @@ int find_legacy_keymap(Context *c, char **ret) {
|
||||
x = strdupcspn(a[1], ",");
|
||||
if (!x)
|
||||
return -ENOMEM;
|
||||
if (startswith_comma(c->x11_layout, x))
|
||||
if (startswith_comma(xc->layout, x))
|
||||
matching = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (matching > 0) {
|
||||
if (isempty(c->x11_model) || streq_ptr(c->x11_model, a[2])) {
|
||||
if (isempty(xc->model) || streq_ptr(xc->model, a[2])) {
|
||||
matching++;
|
||||
|
||||
if (streq_ptr(c->x11_variant, a[3])) {
|
||||
if (streq_ptr(xc->variant, a[3])) {
|
||||
matching++;
|
||||
|
||||
if (streq_ptr(c->x11_options, a[4]))
|
||||
if (streq_ptr(xc->options, a[4]))
|
||||
matching++;
|
||||
}
|
||||
}
|
||||
@ -528,8 +694,7 @@ int find_legacy_keymap(Context *c, char **ret) {
|
||||
|
||||
/* The best matching entry so far, then let's save that */
|
||||
if (matching >= MAX(best_matching, 1u)) {
|
||||
log_debug("Found legacy keymap %s with score %u",
|
||||
a[0], matching);
|
||||
log_debug("Found legacy keymap %s with score %u", a[0], matching);
|
||||
|
||||
if (matching > best_matching) {
|
||||
best_matching = matching;
|
||||
@ -541,18 +706,30 @@ int find_legacy_keymap(Context *c, char **ret) {
|
||||
}
|
||||
}
|
||||
|
||||
if (best_matching < 10 && c->x11_layout) {
|
||||
if (best_matching < 10 && !isempty(xc->layout)) {
|
||||
_cleanup_free_ char *l = NULL, *v = NULL, *converted = NULL;
|
||||
|
||||
/* The best match is only the first part of the X11
|
||||
* keymap. Check if we have a converted map which
|
||||
* matches just the first layout.
|
||||
*/
|
||||
char *l, *v = NULL, *converted;
|
||||
|
||||
l = strndupa_safe(c->x11_layout, strcspn(c->x11_layout, ","));
|
||||
if (c->x11_variant)
|
||||
v = strndupa_safe(c->x11_variant,
|
||||
strcspn(c->x11_variant, ","));
|
||||
r = find_converted_keymap(l, v, &converted);
|
||||
l = strndup(xc->layout, strcspn(xc->layout, ","));
|
||||
if (!l)
|
||||
return -ENOMEM;
|
||||
|
||||
if (!isempty(xc->variant)) {
|
||||
v = strndup(xc->variant, strcspn(xc->variant, ","));
|
||||
if (!v)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
r = find_converted_keymap(
|
||||
&(X11Context) {
|
||||
.layout = l,
|
||||
.variant = v,
|
||||
},
|
||||
&converted);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r > 0)
|
||||
@ -560,26 +737,25 @@ int find_legacy_keymap(Context *c, char **ret) {
|
||||
}
|
||||
|
||||
*ret = TAKE_PTR(new_keymap);
|
||||
return (bool) *ret;
|
||||
return !!*ret;
|
||||
}
|
||||
|
||||
int find_language_fallback(const char *lang, char **language) {
|
||||
int find_language_fallback(const char *lang, char **ret) {
|
||||
const char *map;
|
||||
_cleanup_fclose_ FILE *f = NULL;
|
||||
unsigned n = 0;
|
||||
int r;
|
||||
|
||||
assert(lang);
|
||||
assert(language);
|
||||
assert(ret);
|
||||
|
||||
map = systemd_language_fallback_map();
|
||||
|
||||
f = fopen(map, "re");
|
||||
if (!f)
|
||||
return -errno;
|
||||
|
||||
for (;;) {
|
||||
_cleanup_strv_free_ char **a = NULL;
|
||||
int r;
|
||||
|
||||
r = read_next_mapping(map, 2, 2, f, &n, &a);
|
||||
if (r <= 0)
|
||||
@ -587,45 +763,44 @@ int find_language_fallback(const char *lang, char **language) {
|
||||
|
||||
if (streq(lang, a[0])) {
|
||||
assert(strv_length(a) == 2);
|
||||
*language = TAKE_PTR(a[1]);
|
||||
*ret = TAKE_PTR(a[1]);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
assert_not_reached();
|
||||
}
|
||||
|
||||
int x11_convert_to_vconsole(Context *c) {
|
||||
bool modified = false;
|
||||
const X11Context *xc;
|
||||
|
||||
if (isempty(c->x11_layout)) {
|
||||
assert(c);
|
||||
|
||||
xc = context_get_x11_context_safe(c);
|
||||
|
||||
if (isempty(xc->layout)) {
|
||||
modified =
|
||||
!isempty(c->vc_keymap) ||
|
||||
!isempty(c->vc_keymap_toggle);
|
||||
|
||||
context_free_vconsole(c);
|
||||
context_clear_vconsole(c);
|
||||
} else {
|
||||
_cleanup_free_ char *new_keymap = NULL;
|
||||
int r;
|
||||
|
||||
r = find_converted_keymap(c->x11_layout, c->x11_variant, &new_keymap);
|
||||
r = find_converted_keymap(xc, &new_keymap);
|
||||
if (r == 0)
|
||||
r = find_legacy_keymap(xc, &new_keymap);
|
||||
if (r < 0)
|
||||
return r;
|
||||
else if (r == 0) {
|
||||
r = find_legacy_keymap(c, &new_keymap);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
if (r == 0)
|
||||
/* We search for layout-variant match first, but then we also look
|
||||
* for anything which matches just the layout. So it's accurate to say
|
||||
* that we couldn't find anything which matches the layout. */
|
||||
log_notice("No conversion to virtual console map found for \"%s\".",
|
||||
c->x11_layout);
|
||||
log_notice("No conversion to virtual console map found for \"%s\".", xc->layout);
|
||||
|
||||
if (!streq_ptr(c->vc_keymap, new_keymap)) {
|
||||
free_and_replace(c->vc_keymap, new_keymap);
|
||||
c->vc_keymap_toggle = mfree(c->vc_keymap_toggle);
|
||||
context_clear_vconsole(c);
|
||||
c->vc_keymap = TAKE_PTR(new_keymap);
|
||||
modified = true;
|
||||
}
|
||||
}
|
||||
|
@ -8,16 +8,21 @@
|
||||
#include "hashmap.h"
|
||||
#include "locale-setup.h"
|
||||
|
||||
typedef struct X11Context {
|
||||
char *layout;
|
||||
char *model;
|
||||
char *variant;
|
||||
char *options;
|
||||
} X11Context;
|
||||
|
||||
typedef struct Context {
|
||||
sd_bus_message *locale_cache;
|
||||
LocaleContext locale_context;
|
||||
|
||||
sd_bus_message *x11_cache;
|
||||
struct stat x11_stat;
|
||||
char *x11_layout;
|
||||
char *x11_model;
|
||||
char *x11_variant;
|
||||
char *x11_options;
|
||||
X11Context x11_from_xorg;
|
||||
X11Context x11_from_vc;
|
||||
|
||||
sd_bus_message *vc_cache;
|
||||
struct stat vc_stat;
|
||||
@ -27,9 +32,16 @@ typedef struct Context {
|
||||
Hashmap *polkit_registry;
|
||||
} Context;
|
||||
|
||||
int find_converted_keymap(const char *x11_layout, const char *x11_variant, char **new_keymap);
|
||||
int find_legacy_keymap(Context *c, char **new_keymap);
|
||||
int find_language_fallback(const char *lang, char **language);
|
||||
void x11_context_empty_to_null(X11Context *xc);
|
||||
bool x11_context_is_safe(const X11Context *xc);
|
||||
bool x11_context_equal(const X11Context *a, const X11Context *b);
|
||||
int x11_context_copy(X11Context *dest, const X11Context *src);
|
||||
|
||||
X11Context *context_get_x11_context_safe(Context *c);
|
||||
|
||||
int find_converted_keymap(const X11Context *xc, char **ret);
|
||||
int find_legacy_keymap(const X11Context *xc, char **ret);
|
||||
int find_language_fallback(const char *lang, char **ret);
|
||||
|
||||
int locale_read_data(Context *c, sd_bus_message *m);
|
||||
int vconsole_read_data(Context *c, sd_bus_message *m);
|
||||
|
@ -75,58 +75,6 @@ static int vconsole_reload(sd_bus *bus) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vconsole_convert_to_x11_and_emit(Context *c, sd_bus_message *m) {
|
||||
int r;
|
||||
|
||||
assert(m);
|
||||
|
||||
r = x11_read_data(c, m);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = vconsole_convert_to_x11(c);
|
||||
if (r <= 0)
|
||||
return r;
|
||||
|
||||
/* modified */
|
||||
r = x11_write_data(c);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to write X11 keyboard layout: %m");
|
||||
|
||||
sd_bus_emit_properties_changed(sd_bus_message_get_bus(m),
|
||||
"/org/freedesktop/locale1",
|
||||
"org.freedesktop.locale1",
|
||||
"X11Layout", "X11Model", "X11Variant", "X11Options", NULL);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int x11_convert_to_vconsole_and_emit(Context *c, sd_bus_message *m) {
|
||||
int r;
|
||||
|
||||
assert(m);
|
||||
|
||||
r = vconsole_read_data(c, m);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = x11_convert_to_vconsole(c);
|
||||
if (r <= 0)
|
||||
return r;
|
||||
|
||||
/* modified */
|
||||
r = vconsole_write_data(c);
|
||||
if (r < 0)
|
||||
log_error_errno(r, "Failed to save virtual console keymap: %m");
|
||||
|
||||
sd_bus_emit_properties_changed(sd_bus_message_get_bus(m),
|
||||
"/org/freedesktop/locale1",
|
||||
"org.freedesktop.locale1",
|
||||
"VConsoleKeymap", "VConsoleKeymapToggle", NULL);
|
||||
|
||||
return vconsole_reload(sd_bus_message_get_bus(m));
|
||||
}
|
||||
|
||||
static int property_get_locale(
|
||||
sd_bus *bus,
|
||||
const char *path,
|
||||
@ -136,7 +84,7 @@ static int property_get_locale(
|
||||
void *userdata,
|
||||
sd_bus_error *error) {
|
||||
|
||||
Context *c = userdata;
|
||||
Context *c = ASSERT_PTR(userdata);
|
||||
_cleanup_strv_free_ char **l = NULL;
|
||||
int r;
|
||||
|
||||
@ -160,16 +108,18 @@ static int property_get_vconsole(
|
||||
void *userdata,
|
||||
sd_bus_error *error) {
|
||||
|
||||
Context *c = userdata;
|
||||
Context *c = ASSERT_PTR(userdata);
|
||||
int r;
|
||||
|
||||
assert(property);
|
||||
|
||||
r = vconsole_read_data(c, reply);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (streq(property, "VConsoleKeymap"))
|
||||
return sd_bus_message_append_basic(reply, 's', c->vc_keymap);
|
||||
else if (streq(property, "VConsoleKeymapToggle"))
|
||||
if (streq(property, "VConsoleKeymapToggle"))
|
||||
return sd_bus_message_append_basic(reply, 's', c->vc_keymap_toggle);
|
||||
|
||||
return -EINVAL;
|
||||
@ -184,21 +134,26 @@ static int property_get_xkb(
|
||||
void *userdata,
|
||||
sd_bus_error *error) {
|
||||
|
||||
Context *c = userdata;
|
||||
Context *c = ASSERT_PTR(userdata);
|
||||
const X11Context *xc;
|
||||
int r;
|
||||
|
||||
assert(property);
|
||||
|
||||
r = x11_read_data(c, reply);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
xc = context_get_x11_context_safe(c);
|
||||
|
||||
if (streq(property, "X11Layout"))
|
||||
return sd_bus_message_append_basic(reply, 's', c->x11_layout);
|
||||
else if (streq(property, "X11Model"))
|
||||
return sd_bus_message_append_basic(reply, 's', c->x11_model);
|
||||
else if (streq(property, "X11Variant"))
|
||||
return sd_bus_message_append_basic(reply, 's', c->x11_variant);
|
||||
else if (streq(property, "X11Options"))
|
||||
return sd_bus_message_append_basic(reply, 's', c->x11_options);
|
||||
return sd_bus_message_append_basic(reply, 's', xc->layout);
|
||||
if (streq(property, "X11Model"))
|
||||
return sd_bus_message_append_basic(reply, 's', xc->model);
|
||||
if (streq(property, "X11Variant"))
|
||||
return sd_bus_message_append_basic(reply, 's', xc->variant);
|
||||
if (streq(property, "X11Options"))
|
||||
return sd_bus_message_append_basic(reply, 's', xc->options);
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
@ -243,9 +198,9 @@ static int process_locale_list_item(
|
||||
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Locale assignment %s not valid, refusing.", assignment);
|
||||
}
|
||||
|
||||
static int locale_gen_process_locale(char *new_locale[static _VARIABLE_LC_MAX],
|
||||
sd_bus_error *error) {
|
||||
static int locale_gen_process_locale(char *new_locale[static _VARIABLE_LC_MAX], sd_bus_error *error) {
|
||||
int r;
|
||||
|
||||
assert(new_locale);
|
||||
|
||||
for (LocaleVariable p = 0; p < _VARIABLE_LC_MAX; p++) {
|
||||
@ -263,13 +218,15 @@ static int locale_gen_process_locale(char *new_locale[static _VARIABLE_LC_MAX],
|
||||
SD_BUS_ERROR_INVALID_ARGS,
|
||||
"Specified locale is not installed and non-UTF-8 locale will not be auto-generated: %s",
|
||||
new_locale[p]);
|
||||
} else if (r == -EINVAL) {
|
||||
}
|
||||
if (r == -EINVAL) {
|
||||
log_error_errno(r, "Failed to enable invalid locale %s for generation.", new_locale[p]);
|
||||
return sd_bus_error_setf(error,
|
||||
SD_BUS_ERROR_INVALID_ARGS,
|
||||
"Can not enable locale generation for invalid locale: %s",
|
||||
new_locale[p]);
|
||||
} else if (r < 0) {
|
||||
}
|
||||
if (r < 0) {
|
||||
log_error_errno(r, "Failed to enable locale for generation: %m");
|
||||
return sd_bus_error_set_errnof(error, r, "Failed to enable locale generation: %m");
|
||||
}
|
||||
@ -460,10 +417,31 @@ static int method_set_vc_keyboard(sd_bus_message *m, void *userdata, sd_bus_erro
|
||||
free_and_strdup(&c->vc_keymap_toggle, keymap_toggle) < 0)
|
||||
return -ENOMEM;
|
||||
|
||||
if (convert) {
|
||||
r = x11_read_data(c, m);
|
||||
if (r < 0) {
|
||||
log_error_errno(r, "Failed to read X11 keyboard layout data: %m");
|
||||
return sd_bus_error_set_errnof(error, r, "Failed to read X11 keyboard layout data: %m");
|
||||
}
|
||||
|
||||
r = vconsole_convert_to_x11(c);
|
||||
if (r < 0) {
|
||||
log_error_errno(r, "Failed to convert keymap data: %m");
|
||||
return sd_bus_error_set_errnof(error, r, "Failed to convert keymap data: %m");
|
||||
}
|
||||
|
||||
/* save the result of conversion to emit changed properties later. */
|
||||
convert = r > 0;
|
||||
}
|
||||
|
||||
r = vconsole_write_data(c);
|
||||
if (r < 0) {
|
||||
log_error_errno(r, "Failed to set virtual console keymap: %m");
|
||||
return sd_bus_error_set_errnof(error, r, "Failed to set virtual console keymap: %m");
|
||||
if (r < 0)
|
||||
log_warning_errno(r, "Failed to write virtual console keymap, ignoring: %m");
|
||||
|
||||
if (convert) {
|
||||
r = x11_write_data(c);
|
||||
if (r < 0)
|
||||
log_warning_errno(r, "Failed to write X11 keyboard layout, ignoring: %m");
|
||||
}
|
||||
|
||||
log_info("Changed virtual console keymap to '%s' toggle '%s'",
|
||||
@ -475,13 +453,12 @@ static int method_set_vc_keyboard(sd_bus_message *m, void *userdata, sd_bus_erro
|
||||
sd_bus_message_get_bus(m),
|
||||
"/org/freedesktop/locale1",
|
||||
"org.freedesktop.locale1",
|
||||
"VConsoleKeymap", "VConsoleKeymapToggle", NULL);
|
||||
|
||||
if (convert) {
|
||||
r = vconsole_convert_to_x11_and_emit(c, m);
|
||||
if (r < 0)
|
||||
log_error_errno(r, "Failed to convert keymap data: %m");
|
||||
}
|
||||
"VConsoleKeymap", "VConsoleKeymapToggle",
|
||||
convert ? "X11Layout" : NULL,
|
||||
convert ? "X11Model" : NULL,
|
||||
convert ? "X11Variant" : NULL,
|
||||
convert ? "X11Options" : NULL,
|
||||
NULL);
|
||||
|
||||
return sd_bus_reply_method_return(m, NULL);
|
||||
}
|
||||
@ -589,19 +566,16 @@ static int verify_xkb_rmlvo(const char *model, const char *layout, const char *v
|
||||
|
||||
static int method_set_x11_keyboard(sd_bus_message *m, void *userdata, sd_bus_error *error) {
|
||||
Context *c = ASSERT_PTR(userdata);
|
||||
const char *layout, *model, *variant, *options;
|
||||
int convert, interactive, r;
|
||||
X11Context *xc, in;
|
||||
|
||||
assert(m);
|
||||
|
||||
r = sd_bus_message_read(m, "ssssbb", &layout, &model, &variant, &options, &convert, &interactive);
|
||||
r = sd_bus_message_read(m, "ssssbb", &in.layout, &in.model, &in.variant, &in.options, &convert, &interactive);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
layout = empty_to_null(layout);
|
||||
model = empty_to_null(model);
|
||||
variant = empty_to_null(variant);
|
||||
options = empty_to_null(options);
|
||||
x11_context_empty_to_null(&in);
|
||||
|
||||
r = x11_read_data(c, m);
|
||||
if (r < 0) {
|
||||
@ -609,22 +583,18 @@ static int method_set_x11_keyboard(sd_bus_message *m, void *userdata, sd_bus_err
|
||||
return sd_bus_error_set(error, SD_BUS_ERROR_FAILED, "Failed to read x11 keyboard layout data");
|
||||
}
|
||||
|
||||
if (streq_ptr(layout, c->x11_layout) &&
|
||||
streq_ptr(model, c->x11_model) &&
|
||||
streq_ptr(variant, c->x11_variant) &&
|
||||
streq_ptr(options, c->x11_options))
|
||||
xc = context_get_x11_context_safe(c);
|
||||
|
||||
if (x11_context_equal(xc, &in))
|
||||
return sd_bus_reply_method_return(m, NULL);
|
||||
|
||||
if ((layout && !string_is_safe(layout)) ||
|
||||
(model && !string_is_safe(model)) ||
|
||||
(variant && !string_is_safe(variant)) ||
|
||||
(options && !string_is_safe(options)))
|
||||
if (!x11_context_is_safe(&in))
|
||||
return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Received invalid keyboard data");
|
||||
|
||||
r = verify_xkb_rmlvo(model, layout, variant, options);
|
||||
r = verify_xkb_rmlvo(in.model, in.layout, in.variant, in.options);
|
||||
if (r < 0) {
|
||||
log_error_errno(r, "Cannot compile XKB keymap for new x11 keyboard layout ('%s' / '%s' / '%s' / '%s'): %m",
|
||||
strempty(model), strempty(layout), strempty(variant), strempty(options));
|
||||
strempty(in.model), strempty(in.layout), strempty(in.variant), strempty(in.options));
|
||||
|
||||
if (r == -EOPNOTSUPP)
|
||||
return sd_bus_error_set(error, SD_BUS_ERROR_NOT_SUPPORTED, "Local keyboard configuration not supported on this system.");
|
||||
@ -646,35 +616,46 @@ static int method_set_x11_keyboard(sd_bus_message *m, void *userdata, sd_bus_err
|
||||
if (r == 0)
|
||||
return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
|
||||
|
||||
if (free_and_strdup(&c->x11_layout, layout) < 0 ||
|
||||
free_and_strdup(&c->x11_model, model) < 0 ||
|
||||
free_and_strdup(&c->x11_variant, variant) < 0 ||
|
||||
free_and_strdup(&c->x11_options, options) < 0)
|
||||
return -ENOMEM;
|
||||
r = x11_context_copy(xc, &in);
|
||||
if (r < 0)
|
||||
return log_oom();
|
||||
|
||||
r = x11_write_data(c);
|
||||
if (r < 0) {
|
||||
log_error_errno(r, "Failed to set X11 keyboard layout: %m");
|
||||
return sd_bus_error_set_errnof(error, r, "Failed to set X11 keyboard layout: %m");
|
||||
if (convert) {
|
||||
r = x11_convert_to_vconsole(c);
|
||||
if (r < 0) {
|
||||
log_error_errno(r, "Failed to convert keymap data: %m");
|
||||
return sd_bus_error_set_errnof(error, r, "Failed to convert keymap data: %m");
|
||||
}
|
||||
|
||||
/* save the result of conversion to emit changed properties later. */
|
||||
convert = r > 0;
|
||||
}
|
||||
|
||||
r = vconsole_write_data(c);
|
||||
if (r < 0)
|
||||
log_warning_errno(r, "Failed to update vconsole.conf, ignoring: %m");
|
||||
|
||||
r = x11_write_data(c);
|
||||
if (r < 0)
|
||||
log_warning_errno(r, "Failed to write X11 keyboard layout, ignoring: %m");
|
||||
|
||||
log_info("Changed 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));
|
||||
strempty(in.layout),
|
||||
strempty(in.model),
|
||||
strempty(in.variant),
|
||||
strempty(in.options));
|
||||
|
||||
(void) sd_bus_emit_properties_changed(
|
||||
sd_bus_message_get_bus(m),
|
||||
"/org/freedesktop/locale1",
|
||||
"org.freedesktop.locale1",
|
||||
"X11Layout", "X11Model", "X11Variant", "X11Options", NULL);
|
||||
"X11Layout", "X11Model", "X11Variant", "X11Options",
|
||||
convert ? "VConsoleKeymap" : NULL,
|
||||
convert ? "VConsoleKeymapToggle" : NULL,
|
||||
NULL);
|
||||
|
||||
if (convert) {
|
||||
r = x11_convert_to_vconsole_and_emit(c, m);
|
||||
if (r < 0)
|
||||
log_error_errno(r, "Failed to convert keymap data: %m");
|
||||
}
|
||||
if (convert)
|
||||
(void) vconsole_reload(sd_bus_message_get_bus(m));
|
||||
|
||||
return sd_bus_reply_method_return(m, NULL);
|
||||
}
|
||||
|
@ -26,10 +26,17 @@ TEST(find_converted_keymap) {
|
||||
_cleanup_free_ char *ans = NULL, *ans2 = NULL;
|
||||
int r;
|
||||
|
||||
assert_se(find_converted_keymap("pl", "foobar", &ans) == 0);
|
||||
assert_se(find_converted_keymap(
|
||||
&(X11Context) {
|
||||
.layout = (char*) "pl",
|
||||
.variant = (char*) "foobar",
|
||||
}, &ans) == 0);
|
||||
assert_se(ans == NULL);
|
||||
|
||||
r = find_converted_keymap("pl", NULL, &ans);
|
||||
r = find_converted_keymap(
|
||||
&(X11Context) {
|
||||
.layout = (char*) "pl",
|
||||
}, &ans);
|
||||
if (r == 0) {
|
||||
log_info("Skipping rest of %s: keymaps are not installed", __func__);
|
||||
return;
|
||||
@ -38,81 +45,87 @@ TEST(find_converted_keymap) {
|
||||
assert_se(r == 1);
|
||||
assert_se(streq(ans, "pl"));
|
||||
|
||||
assert_se(find_converted_keymap("pl", "dvorak", &ans2) == 1);
|
||||
assert_se(find_converted_keymap(
|
||||
&(X11Context) {
|
||||
.layout = (char*) "pl",
|
||||
.variant = (char*) "dvorak",
|
||||
}, &ans2) == 1);
|
||||
assert_se(streq(ans2, "pl-dvorak"));
|
||||
}
|
||||
|
||||
TEST(find_legacy_keymap) {
|
||||
Context c = {};
|
||||
X11Context xc = {};
|
||||
_cleanup_free_ char *ans = NULL, *ans2 = NULL;
|
||||
|
||||
c.x11_layout = (char*) "foobar";
|
||||
assert_se(find_legacy_keymap(&c, &ans) == 0);
|
||||
xc.layout = (char*) "foobar";
|
||||
assert_se(find_legacy_keymap(&xc, &ans) == 0);
|
||||
assert_se(ans == NULL);
|
||||
|
||||
c.x11_layout = (char*) "pl";
|
||||
assert_se(find_legacy_keymap(&c, &ans) == 1);
|
||||
xc.layout = (char*) "pl";
|
||||
assert_se(find_legacy_keymap(&xc, &ans) == 1);
|
||||
assert_se(streq(ans, "pl2"));
|
||||
|
||||
c.x11_layout = (char*) "pl,ru";
|
||||
assert_se(find_legacy_keymap(&c, &ans2) == 1);
|
||||
xc.layout = (char*) "pl,ru";
|
||||
assert_se(find_legacy_keymap(&xc, &ans2) == 1);
|
||||
assert_se(streq(ans, "pl2"));
|
||||
}
|
||||
|
||||
TEST(vconsole_convert_to_x11) {
|
||||
_cleanup_(context_clear) Context c = {};
|
||||
X11Context *xc = &c.x11_from_vc;
|
||||
|
||||
log_info("/* test emptying first (:) */");
|
||||
assert_se(free_and_strdup(&c.x11_layout, "foo") >= 0);
|
||||
assert_se(free_and_strdup(&c.x11_variant, "bar") >= 0);
|
||||
assert_se(free_and_strdup(&xc->layout, "foo") >= 0);
|
||||
assert_se(free_and_strdup(&xc->variant, "bar") >= 0);
|
||||
assert_se(vconsole_convert_to_x11(&c) == 1);
|
||||
assert_se(c.x11_layout == NULL);
|
||||
assert_se(c.x11_variant == NULL);
|
||||
assert_se(xc->layout == NULL);
|
||||
assert_se(xc->variant == NULL);
|
||||
|
||||
log_info("/* test emptying second (:) */");
|
||||
|
||||
assert_se(vconsole_convert_to_x11(&c) == 0);
|
||||
assert_se(c.x11_layout == NULL);
|
||||
assert_se(c.x11_variant == NULL);
|
||||
assert_se(xc->layout == NULL);
|
||||
assert_se(xc->variant == NULL);
|
||||
|
||||
log_info("/* test without variant, new mapping (es:) */");
|
||||
assert_se(free_and_strdup(&c.vc_keymap, "es") >= 0);
|
||||
|
||||
assert_se(vconsole_convert_to_x11(&c) == 1);
|
||||
assert_se(streq(c.x11_layout, "es"));
|
||||
assert_se(c.x11_variant == NULL);
|
||||
assert_se(streq(xc->layout, "es"));
|
||||
assert_se(xc->variant == NULL);
|
||||
|
||||
log_info("/* test with known variant, new mapping (es:dvorak) */");
|
||||
assert_se(free_and_strdup(&c.vc_keymap, "es-dvorak") >= 0);
|
||||
|
||||
assert_se(vconsole_convert_to_x11(&c) == 1);
|
||||
assert_se(streq(c.x11_layout, "es"));
|
||||
assert_se(streq(c.x11_variant, "dvorak"));
|
||||
assert_se(streq(xc->layout, "es"));
|
||||
assert_se(streq(xc->variant, "dvorak"));
|
||||
|
||||
log_info("/* test with old mapping (fr:latin9) */");
|
||||
assert_se(free_and_strdup(&c.vc_keymap, "fr-latin9") >= 0);
|
||||
|
||||
assert_se(vconsole_convert_to_x11(&c) == 1);
|
||||
assert_se(streq(c.x11_layout, "fr"));
|
||||
assert_se(streq(c.x11_variant, "latin9"));
|
||||
assert_se(streq(xc->layout, "fr"));
|
||||
assert_se(streq(xc->variant, "latin9"));
|
||||
|
||||
log_info("/* test with a compound mapping (ru,us) */");
|
||||
assert_se(free_and_strdup(&c.vc_keymap, "ru") >= 0);
|
||||
|
||||
assert_se(vconsole_convert_to_x11(&c) == 1);
|
||||
assert_se(streq(c.x11_layout, "ru,us"));
|
||||
assert_se(c.x11_variant == NULL);
|
||||
assert_se(streq(xc->layout, "ru,us"));
|
||||
assert_se(xc->variant == NULL);
|
||||
|
||||
log_info("/* test with a simple mapping (us) */");
|
||||
assert_se(free_and_strdup(&c.vc_keymap, "us") >= 0);
|
||||
|
||||
assert_se(vconsole_convert_to_x11(&c) == 1);
|
||||
assert_se(streq(c.x11_layout, "us"));
|
||||
assert_se(c.x11_variant == NULL);
|
||||
assert_se(streq(xc->layout, "us"));
|
||||
assert_se(xc->variant == NULL);
|
||||
}
|
||||
|
||||
TEST(x11_convert_to_vconsole) {
|
||||
_cleanup_(context_clear) Context c = {};
|
||||
X11Context *xc = &c.x11_from_xorg;
|
||||
int r;
|
||||
|
||||
log_info("/* test emptying first (:) */");
|
||||
@ -126,19 +139,19 @@ TEST(x11_convert_to_vconsole) {
|
||||
assert_se(c.vc_keymap == NULL);
|
||||
|
||||
log_info("/* test without variant, new mapping (es:) */");
|
||||
assert_se(free_and_strdup(&c.x11_layout, "es") >= 0);
|
||||
assert_se(free_and_strdup(&xc->layout, "es") >= 0);
|
||||
|
||||
assert_se(x11_convert_to_vconsole(&c) == 1);
|
||||
assert_se(streq(c.vc_keymap, "es"));
|
||||
|
||||
log_info("/* test with unknown variant, new mapping (es:foobar) */");
|
||||
assert_se(free_and_strdup(&c.x11_variant, "foobar") >= 0);
|
||||
assert_se(free_and_strdup(&xc->variant, "foobar") >= 0);
|
||||
|
||||
assert_se(x11_convert_to_vconsole(&c) == 0);
|
||||
assert_se(streq(c.vc_keymap, "es"));
|
||||
|
||||
log_info("/* test with known variant, new mapping (es:dvorak) */");
|
||||
assert_se(free_and_strdup(&c.x11_variant, "dvorak") >= 0);
|
||||
assert_se(free_and_strdup(&xc->variant, "dvorak") >= 0);
|
||||
|
||||
r = x11_convert_to_vconsole(&c);
|
||||
if (r == 0) {
|
||||
@ -150,30 +163,30 @@ TEST(x11_convert_to_vconsole) {
|
||||
assert_se(streq(c.vc_keymap, "es-dvorak"));
|
||||
|
||||
log_info("/* test with old mapping (fr:latin9) */");
|
||||
assert_se(free_and_strdup(&c.x11_layout, "fr") >= 0);
|
||||
assert_se(free_and_strdup(&c.x11_variant, "latin9") >= 0);
|
||||
assert_se(free_and_strdup(&xc->layout, "fr") >= 0);
|
||||
assert_se(free_and_strdup(&xc->variant, "latin9") >= 0);
|
||||
|
||||
assert_se(x11_convert_to_vconsole(&c) == 1);
|
||||
assert_se(streq(c.vc_keymap, "fr-latin9"));
|
||||
|
||||
log_info("/* test with a compound mapping (us,ru:) */");
|
||||
assert_se(free_and_strdup(&c.x11_layout, "us,ru") >= 0);
|
||||
assert_se(free_and_strdup(&c.x11_variant, NULL) >= 0);
|
||||
assert_se(free_and_strdup(&xc->layout, "us,ru") >= 0);
|
||||
assert_se(free_and_strdup(&xc->variant, NULL) >= 0);
|
||||
|
||||
assert_se(x11_convert_to_vconsole(&c) == 1);
|
||||
assert_se(streq(c.vc_keymap, "us"));
|
||||
|
||||
log_info("/* test with a compound mapping (ru,us:) */");
|
||||
assert_se(free_and_strdup(&c.x11_layout, "ru,us") >= 0);
|
||||
assert_se(free_and_strdup(&c.x11_variant, NULL) >= 0);
|
||||
assert_se(free_and_strdup(&xc->layout, "ru,us") >= 0);
|
||||
assert_se(free_and_strdup(&xc->variant, NULL) >= 0);
|
||||
|
||||
assert_se(x11_convert_to_vconsole(&c) == 1);
|
||||
assert_se(streq(c.vc_keymap, "ru"));
|
||||
|
||||
/* https://bugzilla.redhat.com/show_bug.cgi?id=1333998 */
|
||||
log_info("/* test with a simple new mapping (ru:) */");
|
||||
assert_se(free_and_strdup(&c.x11_layout, "ru") >= 0);
|
||||
assert_se(free_and_strdup(&c.x11_variant, NULL) >= 0);
|
||||
assert_se(free_and_strdup(&xc->layout, "ru") >= 0);
|
||||
assert_se(free_and_strdup(&xc->variant, NULL) >= 0);
|
||||
|
||||
assert_se(x11_convert_to_vconsole(&c) == 0);
|
||||
assert_se(streq(c.vc_keymap, "ru"));
|
||||
|
@ -223,7 +223,7 @@ wait_vconsole_setup() {
|
||||
}
|
||||
|
||||
test_vc_keymap() {
|
||||
local i output
|
||||
local i output vc
|
||||
|
||||
if [[ -z "$(localectl list-keymaps)" ]]; then
|
||||
echo "No vconsole keymap installed, skipping test."
|
||||
@ -240,14 +240,15 @@ test_vc_keymap() {
|
||||
# clear previous conversion from VC -> X11 keymap
|
||||
systemctl stop systemd-localed.service
|
||||
wait_vconsole_setup
|
||||
rm -f /etc/X11/xorg.conf.d/00-keyboard.conf /etc/default/keyboard
|
||||
rm -f /etc/vconsole.conf /etc/X11/xorg.conf.d/00-keyboard.conf /etc/default/keyboard
|
||||
|
||||
# set VC keymap
|
||||
assert_rc 0 localectl set-keymap "$i"
|
||||
output=$(localectl)
|
||||
|
||||
# check VC keymap
|
||||
assert_in "KEYMAP=$i" "$(cat /etc/vconsole.conf)"
|
||||
vc=$(cat /etc/vconsole.conf)
|
||||
assert_in "KEYMAP=$i" "$vc"
|
||||
assert_in "VC Keymap: $i" "$output"
|
||||
|
||||
# check VC -> X11 keymap conversion
|
||||
@ -256,16 +257,31 @@ test_vc_keymap() {
|
||||
assert_in "X11 Model: pc105\+inet" "$output"
|
||||
assert_not_in "X11 Variant:" "$output"
|
||||
assert_in "X11 Options: terminate:ctrl_alt_bksp" "$output"
|
||||
|
||||
assert_in "XKB_LAYOUT=us" "$vc"
|
||||
assert_in "XKB_MODEL=pc105\+inet" "$vc"
|
||||
assert_not_in "XKB_VARIANT" "$vc"
|
||||
assert_in "XKB_OPTIONS=terminate:ctrl_alt_bksp" "$vc"
|
||||
elif [[ "$i" == "us-acentos" ]]; then
|
||||
assert_in "X11 Layout: us" "$output"
|
||||
assert_in 'X11 Model: pc105$' "$output"
|
||||
assert_in "X11 Variant: intl" "$output"
|
||||
assert_in "X11 Options: terminate:ctrl_alt_bksp" "$output"
|
||||
|
||||
assert_in "XKB_LAYOUT=us" "$vc"
|
||||
assert_in "XKB_MODEL=pc105$" "$vc"
|
||||
assert_in "XKB_VARIANT=intl" "$vc"
|
||||
assert_in "XKB_OPTIONS=terminate:ctrl_alt_bksp" "$vc"
|
||||
elif [[ "$i" =~ ^us-.* ]]; then
|
||||
assert_in "X11 Layout: .unset." "$output"
|
||||
assert_not_in "X11 Model:" "$output"
|
||||
assert_not_in "X11 Variant:" "$output"
|
||||
assert_not_in "X11 Options:" "$output"
|
||||
|
||||
assert_not_in "XKB_LAYOUT" "$vc"
|
||||
assert_not_in "XKB_MODEL" "$vc"
|
||||
assert_not_in "XKB_VARIANT" "$vc"
|
||||
assert_not_in "XKB_OPTIONS" "$vc"
|
||||
fi
|
||||
done
|
||||
|
||||
@ -304,6 +320,12 @@ XKBOPTIONS=terminate:ctrl_alt_bksp"
|
||||
assert_in 'Option "XkbModel" "pc105\+inet"' "$output"
|
||||
assert_in 'Option "XkbVariant" "intl"' "$output"
|
||||
assert_in 'Option "XkbOptions" "terminate:ctrl_alt_bksp"' "$output"
|
||||
|
||||
output=$(cat /etc/vconsole.conf)
|
||||
assert_in 'XKB_LAYOUT=us' "$output"
|
||||
assert_in 'XKB_MODEL=pc105\+inet' "$output"
|
||||
assert_in 'XKB_VARIANT=intl' "$output"
|
||||
assert_in 'XKB_OPTIONS=terminate:ctrl_alt_bksp' "$output"
|
||||
fi
|
||||
|
||||
output=$(localectl)
|
||||
@ -328,6 +350,12 @@ XKBVARIANT=intl"
|
||||
assert_in 'Option "XkbModel" "pc105\+inet"' "$output"
|
||||
assert_in 'Option "XkbVariant" "intl"' "$output"
|
||||
assert_not_in 'Option "XkbOptions"' "$output"
|
||||
|
||||
output=$(cat /etc/vconsole.conf)
|
||||
assert_in 'XKB_LAYOUT=us' "$output"
|
||||
assert_in 'XKB_MODEL=pc105\+inet' "$output"
|
||||
assert_in 'XKB_VARIANT=intl' "$output"
|
||||
assert_not_in 'XKB_OPTIONS' "$output"
|
||||
fi
|
||||
|
||||
output=$(localectl)
|
||||
@ -351,6 +379,12 @@ XKBMODEL=pc105+inet"
|
||||
assert_in 'Option "XkbModel" "pc105\+inet"' "$output"
|
||||
assert_not_in 'Option "XkbVariant"' "$output"
|
||||
assert_not_in 'Option "XkbOptions"' "$output"
|
||||
|
||||
output=$(cat /etc/vconsole.conf)
|
||||
assert_in 'XKB_LAYOUT=us' "$output"
|
||||
assert_in 'XKB_MODEL=pc105\+inet' "$output"
|
||||
assert_not_in 'XKB_VARIANT' "$output"
|
||||
assert_not_in 'XKB_OPTIONS' "$output"
|
||||
fi
|
||||
|
||||
output=$(localectl)
|
||||
@ -373,6 +407,12 @@ XKBMODEL=pc105+inet"
|
||||
assert_not_in 'Option "XkbModel"' "$output"
|
||||
assert_not_in 'Option "XkbVariant"' "$output"
|
||||
assert_not_in 'Option "XkbOptions"' "$output"
|
||||
|
||||
output=$(cat /etc/vconsole.conf)
|
||||
assert_in 'XKB_LAYOUT=us' "$output"
|
||||
assert_not_in 'XKB_MODEL' "$output"
|
||||
assert_not_in 'XKB_VARIANT' "$output"
|
||||
assert_not_in 'XKB_OPTIONS' "$output"
|
||||
fi
|
||||
|
||||
output=$(localectl)
|
||||
@ -383,7 +423,7 @@ XKBMODEL=pc105+inet"
|
||||
|
||||
# gets along without config file
|
||||
systemctl stop systemd-localed.service
|
||||
rm -f /etc/X11/xorg.conf.d/00-keyboard.conf /etc/default/keyboard
|
||||
rm -f /etc/vconsole.conf /etc/X11/xorg.conf.d/00-keyboard.conf /etc/default/keyboard
|
||||
output=$(localectl)
|
||||
assert_in "X11 Layout: .unset." "$output"
|
||||
assert_not_in "X11 Model:" "$output"
|
||||
|
Loading…
Reference in New Issue
Block a user