Merge pull request #26219 from yuwata/localed-follow-ups

locale: check conversion before polkit
This commit is contained in:
Zbigniew Jędrzejewski-Szmek
2023-02-01 17:18:35 +01:00
committed by GitHub
5 changed files with 470 additions and 297 deletions
+144 -139
View File
@@ -56,7 +56,7 @@ static const char* systemd_language_fallback_map(void) {
return SYSTEMD_LANGUAGE_FALLBACK_MAP;
}
static void x11_context_clear(X11Context *xc) {
void x11_context_clear(X11Context *xc) {
assert(xc);
xc->layout = mfree(xc->layout);
@@ -65,7 +65,16 @@ static void x11_context_clear(X11Context *xc) {
xc->variant = mfree(xc->variant);
}
static bool x11_context_isempty(const X11Context *xc) {
void x11_context_replace(X11Context *dest, X11Context *src) {
assert(dest);
assert(src);
x11_context_clear(dest);
*dest = *src;
*src = (X11Context) {};
}
bool x11_context_isempty(const X11Context *xc) {
assert(xc);
return
@@ -152,11 +161,74 @@ static void context_clear_x11(Context *c) {
x11_context_clear(&c->x11_from_vc);
}
static void context_clear_vconsole(Context *c) {
assert(c);
void vc_context_clear(VCContext *vc) {
assert(vc);
c->vc_keymap = mfree(c->vc_keymap);
c->vc_keymap_toggle = mfree(c->vc_keymap_toggle);
vc->keymap = mfree(vc->keymap);
vc->toggle = mfree(vc->toggle);
}
void vc_context_replace(VCContext *dest, VCContext *src) {
assert(dest);
assert(src);
vc_context_clear(dest);
*dest = *src;
*src = (VCContext) {};
}
bool vc_context_isempty(const VCContext *vc) {
assert(vc);
return
isempty(vc->keymap) &&
isempty(vc->toggle);
}
void vc_context_empty_to_null(VCContext *vc) {
assert(vc);
/* Do not call vc_context_clear() for the passed object. */
vc->keymap = empty_to_null(vc->keymap);
vc->toggle = empty_to_null(vc->toggle);
}
bool vc_context_equal(const VCContext *a, const VCContext *b) {
assert(a);
assert(b);
return
streq_ptr(a->keymap, b->keymap) &&
streq_ptr(a->toggle, b->toggle);
}
int vc_context_copy(VCContext *dest, const VCContext *src) {
bool modified;
int r;
assert(dest);
if (dest == src)
return 0;
if (!src) {
modified = !vc_context_isempty(dest);
vc_context_clear(dest);
return modified;
}
r = free_and_strdup(&dest->keymap, src->keymap);
if (r < 0)
return r;
modified = r > 0;
r = free_and_strdup(&dest->toggle, src->toggle);
if (r < 0)
return r;
modified = modified || r > 0;
return modified;
}
void context_clear(Context *c) {
@@ -164,7 +236,7 @@ void context_clear(Context *c) {
locale_context_clear(&c->locale_context);
context_clear_x11(c);
context_clear_vconsole(c);
vc_context_clear(&c->vc);
c->locale_cache = sd_bus_message_unref(c->locale_cache);
c->x11_cache = sd_bus_message_unref(c->x11_cache);
@@ -173,7 +245,7 @@ void context_clear(Context *c) {
c->polkit_registry = bus_verify_polkit_async_registry_free(c->polkit_registry);
};
static X11Context *context_get_x11_context(Context *c) {
X11Context *context_get_x11_context(Context *c) {
assert(c);
if (!x11_context_isempty(&c->x11_from_vc))
@@ -182,12 +254,7 @@ static X11Context *context_get_x11_context(Context *c) {
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;
return &c->x11_from_vc;
}
int locale_read_data(Context *c, sd_bus_message *m) {
@@ -223,7 +290,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_clear_vconsole(c);
vc_context_clear(&c->vc);
return 0;
}
if (fd < 0)
@@ -237,12 +304,12 @@ int vconsole_read_data(Context *c, sd_bus_message *m) {
return 0;
c->vc_stat = st;
context_clear_vconsole(c);
vc_context_clear(&c->vc);
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", &c->vc.keymap,
"KEYMAP_TOGGLE", &c->vc.toggle,
"XKBLAYOUT", &c->x11_from_vc.layout,
"XKBMODEL", &c->x11_from_vc.model,
"XKBVARIANT", &c->x11_from_vc.variant,
@@ -258,15 +325,6 @@ int x11_read_data(Context *c, sd_bus_message *m) {
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)
@@ -356,9 +414,6 @@ 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;
}
@@ -371,36 +426,31 @@ int vconsole_write_data(Context *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;
r = strv_env_assign(&l, "KEYMAP", empty_to_null(c->vc_keymap));
r = strv_env_assign(&l, "KEYMAP", empty_to_null(c->vc.keymap));
if (r < 0)
return r;
r = strv_env_assign(&l, "KEYMAP_TOGGLE", empty_to_null(c->vc_keymap_toggle));
r = strv_env_assign(&l, "KEYMAP_TOGGLE", empty_to_null(c->vc.toggle));
if (r < 0)
return r;
r = strv_env_assign(&l, "XKBLAYOUT", xc ? empty_to_null(xc->layout) : NULL);
r = strv_env_assign(&l, "XKBLAYOUT", empty_to_null(xc->layout));
if (r < 0)
return r;
r = strv_env_assign(&l, "XKBMODEL", xc ? empty_to_null(xc->model) : NULL);
r = strv_env_assign(&l, "XKBMODEL", empty_to_null(xc->model));
if (r < 0)
return r;
r = strv_env_assign(&l, "XKBVARIANT", xc ? empty_to_null(xc->variant) : NULL);
r = strv_env_assign(&l, "XKBVARIANT", empty_to_null(xc->variant));
if (r < 0)
return r;
r = strv_env_assign(&l, "XKBOPTIONS", xc ? empty_to_null(xc->options) : NULL);
r = strv_env_assign(&l, "XKBOPTIONS", empty_to_null(xc->options));
if (r < 0)
return r;
@@ -431,7 +481,7 @@ int x11_write_data(Context *c) {
assert(c);
xc = context_get_x11_context(c);
if (!xc) {
if (x11_context_isempty(xc)) {
if (unlink("/etc/X11/xorg.conf.d/00-keyboard.conf") < 0)
return errno == ENOENT ? 0 : -errno;
@@ -517,7 +567,7 @@ static int read_next_mapping(
length = strv_length(b);
if (length < min_fields || length > max_fields) {
log_warning("Invalid line %s:%u, ignoring.", strna(filename), *n);
log_debug("Invalid line %s:%u, ignoring.", strna(filename), *n);
continue;
}
@@ -530,70 +580,46 @@ static int read_next_mapping(
return 0;
}
int vconsole_convert_to_x11(Context *c) {
int r, modified = -1;
X11Context *xc;
int vconsole_convert_to_x11(const VCContext *vc, X11Context *ret) {
_cleanup_fclose_ FILE *f = NULL;
const char *map;
int r;
assert(c);
assert(vc);
assert(ret);
/* 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 = !x11_context_isempty(xc);
context_clear_x11(c);
} else {
_cleanup_fclose_ FILE *f = NULL;
const char *map;
map = systemd_kbd_model_map();
f = fopen(map, "re");
if (!f)
return -errno;
for (unsigned n = 0;;) {
_cleanup_strv_free_ char **a = NULL;
r = read_next_mapping(map, 5, UINT_MAX, f, &n, &a);
if (r < 0)
return r;
if (r == 0)
break;
if (!streq(c->vc_keymap, a[0]))
continue;
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;
}
if (isempty(vc->keymap)) {
*ret = (X11Context) {};
return 0;
}
if (modified > 0)
log_info("Changing X11 keyboard layout to '%s' model '%s' variant '%s' options '%s'",
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);
else
log_debug("X11 keyboard layout did not need to be modified.");
map = systemd_kbd_model_map();
f = fopen(map, "re");
if (!f)
return -errno;
return modified > 0;
for (unsigned n = 0;;) {
_cleanup_strv_free_ char **a = NULL;
r = read_next_mapping(map, 5, UINT_MAX, f, &n, &a);
if (r < 0)
return r;
if (r == 0) {
*ret = (X11Context) {};
return 0;
}
if (!streq(vc->keymap, a[0]))
continue;
return x11_context_copy(ret,
&(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]),
});
}
}
int find_converted_keymap(const X11Context *xc, char **ret) {
@@ -769,49 +795,28 @@ int find_language_fallback(const char *lang, char **ret) {
}
}
int x11_convert_to_vconsole(Context *c) {
bool modified = false;
const X11Context *xc;
int x11_convert_to_vconsole(const X11Context *xc, VCContext *ret) {
_cleanup_free_ char *keymap = NULL;
int r;
assert(c);
xc = context_get_x11_context_safe(c);
assert(xc);
assert(ret);
if (isempty(xc->layout)) {
modified =
!isempty(c->vc_keymap) ||
!isempty(c->vc_keymap_toggle);
context_clear_vconsole(c);
} else {
_cleanup_free_ char *new_keymap = NULL;
int r;
r = find_converted_keymap(xc, &new_keymap);
if (r == 0)
r = find_legacy_keymap(xc, &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\".", xc->layout);
if (!streq_ptr(c->vc_keymap, new_keymap)) {
context_clear_vconsole(c);
c->vc_keymap = TAKE_PTR(new_keymap);
modified = true;
}
*ret = (VCContext) {};
return 0;
}
if (modified)
log_info("Changing virtual console keymap to '%s' toggle '%s'",
strempty(c->vc_keymap), strempty(c->vc_keymap_toggle));
else
log_debug("Virtual console keymap was not modified.");
r = find_converted_keymap(xc, &keymap);
if (r == 0)
r = find_legacy_keymap(xc, &keymap);
if (r < 0)
return r;
return modified;
*ret = (VCContext) {
.keymap = TAKE_PTR(keymap),
};
return 0;
}
bool locale_gen_check_available(void) {
+19 -5
View File
@@ -15,6 +15,11 @@ typedef struct X11Context {
char *options;
} X11Context;
typedef struct VCContext {
char *keymap;
char *toggle;
} VCContext;
typedef struct Context {
sd_bus_message *locale_cache;
LocaleContext locale_context;
@@ -26,18 +31,27 @@ typedef struct Context {
sd_bus_message *vc_cache;
struct stat vc_stat;
char *vc_keymap;
char *vc_keymap_toggle;
VCContext vc;
Hashmap *polkit_registry;
} Context;
void x11_context_clear(X11Context *xc);
void x11_context_replace(X11Context *dest, X11Context *src);
bool x11_context_isempty(const X11Context *xc);
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);
X11Context *context_get_x11_context(Context *c);
void vc_context_clear(VCContext *vc);
void vc_context_replace(VCContext *dest, VCContext *src);
bool vc_context_isempty(const VCContext *vc);
void vc_context_empty_to_null(VCContext *vc);
bool vc_context_equal(const VCContext *a, const VCContext *b);
int vc_context_copy(VCContext *dest, const VCContext *src);
int find_converted_keymap(const X11Context *xc, char **ret);
int find_legacy_keymap(const X11Context *xc, char **ret);
@@ -48,9 +62,9 @@ int vconsole_read_data(Context *c, sd_bus_message *m);
int x11_read_data(Context *c, sd_bus_message *m);
void context_clear(Context *c);
int vconsole_convert_to_x11(Context *c);
int vconsole_convert_to_x11(const VCContext *vc, X11Context *ret);
int vconsole_write_data(Context *c);
int x11_convert_to_vconsole(Context *c);
int x11_convert_to_vconsole(const X11Context *xc, VCContext *ret);
int x11_write_data(Context *c);
bool locale_gen_check_available(void);
+119 -67
View File
@@ -118,9 +118,9 @@ static int property_get_vconsole(
return r;
if (streq(property, "VConsoleKeymap"))
return sd_bus_message_append_basic(reply, 's', c->vc_keymap);
return sd_bus_message_append_basic(reply, 's', c->vc.keymap);
if (streq(property, "VConsoleKeymapToggle"))
return sd_bus_message_append_basic(reply, 's', c->vc_keymap_toggle);
return sd_bus_message_append_basic(reply, 's', c->vc.toggle);
return -EINVAL;
}
@@ -140,11 +140,15 @@ static int property_get_xkb(
assert(property);
r = vconsole_read_data(c, reply);
if (r < 0)
return r;
r = x11_read_data(c, reply);
if (r < 0)
return r;
xc = context_get_x11_context_safe(c);
xc = context_get_x11_context(c);
if (streq(property, "X11Layout"))
return sd_bus_message_append_basic(reply, 's', xc->layout);
@@ -252,11 +256,11 @@ static int method_set_locale(sd_bus_message *m, void *userdata, sd_bus_error *er
r = sd_bus_message_read_strv(m, &l);
if (r < 0)
return r;
return bus_log_parse_error(r);
r = sd_bus_message_read_basic(m, 'b', &interactive);
if (r < 0)
return r;
return bus_log_parse_error(r);
use_localegen = locale_gen_check_available();
@@ -269,7 +273,7 @@ static int method_set_locale(sd_bus_message *m, void *userdata, sd_bus_error *er
new_locale[VARIABLE_LANG] = strdup(l[0]);
if (!new_locale[VARIABLE_LANG])
return -ENOMEM;
return log_oom();
l = strv_free(l);
}
@@ -303,7 +307,7 @@ static int method_set_locale(sd_bus_message *m, void *userdata, sd_bus_error *er
/* Merge with the current settings */
r = locale_context_merge(&c->locale_context, new_locale);
if (r < 0)
return r;
return log_oom();
locale_variables_simplify(new_locale);
@@ -366,26 +370,21 @@ static int method_set_locale(sd_bus_message *m, void *userdata, sd_bus_error *er
}
static int method_set_vc_keyboard(sd_bus_message *m, void *userdata, sd_bus_error *error) {
_cleanup_(x11_context_clear) X11Context converted = {};
Context *c = ASSERT_PTR(userdata);
const char *keymap, *keymap_toggle;
int convert, interactive, r;
bool x_needs_update;
VCContext in;
assert(m);
r = sd_bus_message_read(m, "ssbb", &keymap, &keymap_toggle, &convert, &interactive);
r = sd_bus_message_read(m, "ssbb", &in.keymap, &in.toggle, &convert, &interactive);
if (r < 0)
return r;
return bus_log_parse_error(r);
keymap = empty_to_null(keymap);
keymap_toggle = empty_to_null(keymap_toggle);
vc_context_empty_to_null(&in);
r = vconsole_read_data(c, m);
if (r < 0) {
log_error_errno(r, "Failed to read virtual console keymap data: %m");
return sd_bus_error_set_errnof(error, r, "Failed to read virtual console keymap data: %m");
}
FOREACH_STRING(name, keymap ?: keymap_toggle, keymap ? keymap_toggle : NULL) {
FOREACH_STRING(name, in.keymap ?: in.toggle, in.keymap ? in.toggle : NULL) {
r = keymap_exists(name); /* This also verifies that the keymap name is kosher. */
if (r < 0) {
log_error_errno(r, "Failed to check keymap %s: %m", name);
@@ -395,8 +394,37 @@ static int method_set_vc_keyboard(sd_bus_message *m, void *userdata, sd_bus_erro
return sd_bus_error_setf(error, SD_BUS_ERROR_FAILED, "Keymap %s is not installed.", name);
}
if (streq_ptr(keymap, c->vc_keymap) &&
streq_ptr(keymap_toggle, c->vc_keymap_toggle))
r = vconsole_read_data(c, m);
if (r < 0) {
log_error_errno(r, "Failed to read virtual console keymap data: %m");
return sd_bus_error_set_errnof(error, r, "Failed to read virtual console keymap data: %m");
}
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");
}
if (convert) {
r = vconsole_convert_to_x11(&in, &converted);
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");
}
if (x11_context_isempty(&converted))
log_notice("No conversion found for virtual console keymap \"%s\".", strempty(in.keymap));
else
log_info("The virtual console keymap '%s' is converted to X11 keyboard layout '%s' model '%s' variant '%s' options '%s'",
in.keymap, strempty(converted.layout), strempty(converted.model), strempty(converted.variant), strempty(converted.options));
/* save the result of conversion to emit changed properties later. */
x_needs_update = !x11_context_equal(&c->x11_from_vc, &converted) || !x11_context_equal(&c->x11_from_xorg, &converted);
} else
x_needs_update = !x11_context_equal(&c->x11_from_vc, &c->x11_from_xorg);
if (vc_context_equal(&c->vc, &in) && !x_needs_update)
return sd_bus_reply_method_return(m, NULL);
r = bus_verify_polkit_async(
@@ -413,39 +441,42 @@ static int method_set_vc_keyboard(sd_bus_message *m, void *userdata, sd_bus_erro
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->vc_keymap, keymap) < 0 ||
free_and_strdup(&c->vc_keymap_toggle, keymap_toggle) < 0)
return -ENOMEM;
r = vc_context_copy(&c->vc, &in);
if (r < 0)
return log_oom();
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");
if (x_needs_update) {
if (convert) {
r = x11_context_copy(&c->x11_from_vc, &converted);
if (r < 0)
return log_oom();
x11_context_replace(&c->x11_from_xorg, &converted);
} else {
const X11Context *xc = context_get_x11_context(c);
/* Even if the conversion is not requested, sync the two X11 contexts. */
r = x11_context_copy(&c->x11_from_vc, xc);
if (r < 0)
return log_oom();
r = x11_context_copy(&c->x11_from_xorg, xc);
if (r < 0)
return log_oom();
}
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_warning_errno(r, "Failed to write virtual console keymap, ignoring: %m");
if (convert) {
if (x_needs_update) {
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'",
strempty(c->vc_keymap), strempty(c->vc_keymap_toggle));
strempty(c->vc.keymap), strempty(c->vc.toggle));
(void) vconsole_reload(sd_bus_message_get_bus(m));
@@ -454,10 +485,10 @@ static int method_set_vc_keyboard(sd_bus_message *m, void *userdata, sd_bus_erro
"/org/freedesktop/locale1",
"org.freedesktop.locale1",
"VConsoleKeymap", "VConsoleKeymapToggle",
convert ? "X11Layout" : NULL,
convert ? "X11Model" : NULL,
convert ? "X11Variant" : NULL,
convert ? "X11Options" : NULL,
x_needs_update ? "X11Layout" : NULL,
x_needs_update ? "X11Model" : NULL,
x_needs_update ? "X11Variant" : NULL,
x_needs_update ? "X11Options" : NULL,
NULL);
return sd_bus_reply_method_return(m, NULL);
@@ -565,29 +596,19 @@ static int verify_xkb_rmlvo(const char *model, const char *layout, const char *v
#endif
static int method_set_x11_keyboard(sd_bus_message *m, void *userdata, sd_bus_error *error) {
_cleanup_(vc_context_clear) VCContext converted = {};
Context *c = ASSERT_PTR(userdata);
int convert, interactive, r;
X11Context *xc, in;
X11Context in;
assert(m);
r = sd_bus_message_read(m, "ssssbb", &in.layout, &in.model, &in.variant, &in.options, &convert, &interactive);
if (r < 0)
return r;
return bus_log_parse_error(r);
x11_context_empty_to_null(&in);
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(error, SD_BUS_ERROR_FAILED, "Failed to read x11 keyboard layout data");
}
xc = context_get_x11_context_safe(c);
if (x11_context_equal(xc, &in))
return sd_bus_reply_method_return(m, NULL);
if (!x11_context_is_safe(&in))
return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Received invalid keyboard data");
@@ -602,6 +623,41 @@ static int method_set_x11_keyboard(sd_bus_message *m, void *userdata, sd_bus_err
return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Specified keymap cannot be compiled, refusing as invalid.");
}
r = vconsole_read_data(c, m);
if (r < 0) {
log_error_errno(r, "Failed to read virtual console keymap data: %m");
return sd_bus_error_set_errnof(error, r, "Failed to read virtual console keymap data: %m");
}
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(error, SD_BUS_ERROR_FAILED, "Failed to read x11 keyboard layout data");
}
if (convert) {
r = x11_convert_to_vconsole(&in, &converted);
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");
}
if (vc_context_isempty(&converted))
/* 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\".", strempty(in.layout));
else
log_info("The X11 keyboard layout '%s' is converted to virtual console keymap '%s'",
in.layout, converted.keymap);
/* save the result of conversion to emit changed properties later. */
convert = !vc_context_equal(&c->vc, &converted);
}
if (x11_context_equal(&c->x11_from_vc, &in) && x11_context_equal(&c->x11_from_xorg, &in) && !convert)
return sd_bus_reply_method_return(m, NULL);
r = bus_verify_polkit_async(
m,
CAP_SYS_ADMIN,
@@ -616,20 +672,16 @@ 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 */
r = x11_context_copy(xc, &in);
r = x11_context_copy(&c->x11_from_vc, &in);
if (r < 0)
return log_oom();
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");
}
r = x11_context_copy(&c->x11_from_xorg, &in);
if (r < 0)
return log_oom();
/* save the result of conversion to emit changed properties later. */
convert = r > 0;
}
if (convert)
vc_context_replace(&c->vc, &converted);
r = vconsole_write_data(c);
if (r < 0)
+66 -86
View File
@@ -71,125 +71,105 @@ TEST(find_legacy_keymap) {
}
TEST(vconsole_convert_to_x11) {
_cleanup_(context_clear) Context c = {};
X11Context *xc = &c.x11_from_vc;
_cleanup_(x11_context_clear) X11Context xc = {};
_cleanup_(vc_context_clear) VCContext vc = {};
log_info("/* test emptying first (:) */");
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(xc->layout == NULL);
assert_se(xc->variant == NULL);
log_info("/* test emptying second (:) */");
assert_se(vconsole_convert_to_x11(&c) == 0);
assert_se(xc->layout == NULL);
assert_se(xc->variant == NULL);
log_info("/* test empty keymap */");
assert_se(vconsole_convert_to_x11(&vc, &xc) >= 0);
assert_se(x11_context_isempty(&xc));
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(xc->layout, "es"));
assert_se(xc->variant == NULL);
assert_se(free_and_strdup(&vc.keymap, "es") >= 0);
assert_se(vconsole_convert_to_x11(&vc, &xc) >= 0);
assert_se(streq(xc.layout, "es"));
assert_se(xc.variant == NULL);
x11_context_clear(&xc);
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(xc->layout, "es"));
assert_se(streq(xc->variant, "dvorak"));
assert_se(free_and_strdup(&vc.keymap, "es-dvorak") >= 0);
assert_se(vconsole_convert_to_x11(&vc, &xc) >= 0);
assert_se(streq(xc.layout, "es"));
assert_se(streq(xc.variant, "dvorak"));
x11_context_clear(&xc);
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(xc->layout, "fr"));
assert_se(streq(xc->variant, "latin9"));
assert_se(free_and_strdup(&vc.keymap, "fr-latin9") >= 0);
assert_se(vconsole_convert_to_x11(&vc, &xc) >= 0);
assert_se(streq(xc.layout, "fr"));
assert_se(streq(xc.variant, "latin9"));
x11_context_clear(&xc);
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(xc->layout, "ru,us"));
assert_se(xc->variant == NULL);
assert_se(free_and_strdup(&vc.keymap, "ru") >= 0);
assert_se(vconsole_convert_to_x11(&vc, &xc) >= 0);
assert_se(streq(xc.layout, "ru,us"));
assert_se(xc.variant == NULL);
x11_context_clear(&xc);
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(xc->layout, "us"));
assert_se(xc->variant == NULL);
assert_se(free_and_strdup(&vc.keymap, "us") >= 0);
assert_se(vconsole_convert_to_x11(&vc, &xc) >= 0);
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;
_cleanup_(x11_context_clear) X11Context xc = {};
_cleanup_(vc_context_clear) VCContext vc = {};
log_info("/* test emptying first (:) */");
assert_se(free_and_strdup(&c.vc_keymap, "foobar") >= 0);
assert_se(x11_convert_to_vconsole(&c) == 1);
assert_se(c.vc_keymap == NULL);
log_info("/* test emptying second (:) */");
assert_se(x11_convert_to_vconsole(&c) == 0);
assert_se(c.vc_keymap == NULL);
log_info("/* test empty layout (:) */");
assert_se(x11_convert_to_vconsole(&xc, &vc) >= 0);
assert_se(vc_context_isempty(&vc));
log_info("/* test without variant, new mapping (es:) */");
assert_se(free_and_strdup(&xc->layout, "es") >= 0);
assert_se(x11_convert_to_vconsole(&c) == 1);
assert_se(streq(c.vc_keymap, "es"));
assert_se(free_and_strdup(&xc.layout, "es") >= 0);
assert_se(x11_convert_to_vconsole(&xc, &vc) >= 0);
assert_se(streq(vc.keymap, "es"));
vc_context_clear(&vc);
log_info("/* test with unknown variant, new mapping (es:foobar) */");
assert_se(free_and_strdup(&xc->variant, "foobar") >= 0);
assert_se(x11_convert_to_vconsole(&c) == 0);
assert_se(streq(c.vc_keymap, "es"));
assert_se(free_and_strdup(&xc.variant, "foobar") >= 0);
assert_se(x11_convert_to_vconsole(&xc, &vc) >= 0);
assert_se(streq(vc.keymap, "es"));
vc_context_clear(&vc);
log_info("/* test with known variant, new mapping (es:dvorak) */");
assert_se(free_and_strdup(&xc->variant, "dvorak") >= 0);
r = x11_convert_to_vconsole(&c);
if (r == 0) {
assert_se(free_and_strdup(&xc.variant, "dvorak") >= 0);
assert_se(x11_convert_to_vconsole(&xc, &vc) >= 0);
if (vc_context_isempty(&vc)) {
log_info("Skipping rest of %s: keymaps are not installed", __func__);
return;
}
assert_se(r == 1);
assert_se(streq(c.vc_keymap, "es-dvorak"));
assert_se(streq(vc.keymap, "es-dvorak"));
vc_context_clear(&vc);
log_info("/* test with old mapping (fr:latin9) */");
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"));
assert_se(free_and_strdup(&xc.layout, "fr") >= 0);
assert_se(free_and_strdup(&xc.variant, "latin9") >= 0);
assert_se(x11_convert_to_vconsole(&xc, &vc) >= 0);
assert_se(streq(vc.keymap, "fr-latin9"));
vc_context_clear(&vc);
log_info("/* test with a compound mapping (us,ru:) */");
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"));
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(&xc, &vc) >= 0);
assert_se(streq(vc.keymap, "us"));
vc_context_clear(&vc);
log_info("/* test with a compound mapping (ru,us:) */");
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"));
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(&xc, &vc) >= 0);
assert_se(streq(vc.keymap, "ru"));
vc_context_clear(&vc);
/* https://bugzilla.redhat.com/show_bug.cgi?id=1333998 */
log_info("/* test with a simple new mapping (ru:) */");
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"));
assert_se(free_and_strdup(&xc.layout, "ru") >= 0);
assert_se(free_and_strdup(&xc.variant, NULL) >= 0);
assert_se(x11_convert_to_vconsole(&xc, &vc) >= 0);
assert_se(streq(vc.keymap, "ru"));
}
static int intro(void) {
+122
View File
@@ -431,12 +431,134 @@ XKBMODEL=pc105+inet"
assert_not_in "X11 Options:" "$output"
}
test_convert() {
if [[ -z "$(localectl list-keymaps)" ]]; then
echo "No vconsole keymap installed, skipping test."
return
fi
if [[ -z "$(localectl list-x11-keymap-layouts)" ]]; then
echo "No x11 keymap installed, skipping test."
return
fi
backup_keymap
trap restore_keymap RETURN
# clear previous settings
systemctl stop systemd-localed.service
wait_vconsole_setup
rm -f /etc/vconsole.conf /etc/X11/xorg.conf.d/00-keyboard.conf /etc/default/keyboard
# set VC keymap without conversion
assert_rc 0 localectl --no-convert set-keymap us
output=$(localectl)
# check VC keymap
vc=$(cat /etc/vconsole.conf)
assert_in "KEYMAP=us" "$vc"
assert_in "VC Keymap: us" "$output"
# check VC -> X11 keymap conversion (nothing set)
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 "XKBLAYOUT=" "$vc"
assert_not_in "XKBMODEL=" "$vc"
assert_not_in "XKBVARIANT=" "$vc"
assert_not_in "XKBOPTIONS=" "$vc"
# set VC keymap with conversion
assert_rc 0 localectl set-keymap us
output=$(localectl)
# check VC keymap
vc=$(cat /etc/vconsole.conf)
assert_in "KEYMAP=us" "$vc"
assert_in "VC Keymap: us" "$output"
# check VC -> X11 keymap conversion
assert_in "X11 Layout: us" "$output"
assert_in "X11 Model: pc105\+inet" "$output"
assert_not_in "X11 Variant:" "$output"
assert_in "X11 Options: terminate:ctrl_alt_bksp" "$output"
assert_in "XKBLAYOUT=us" "$vc"
assert_in "XKBMODEL=pc105\+inet" "$vc"
assert_not_in "XKBVARIANT" "$vc"
assert_in "XKBOPTIONS=terminate:ctrl_alt_bksp" "$vc"
# clear previous settings
systemctl stop systemd-localed.service
wait_vconsole_setup
rm -f /etc/vconsole.conf /etc/X11/xorg.conf.d/00-keyboard.conf /etc/default/keyboard
# set x11 keymap (layout) without conversion
assert_rc 0 localectl --no-convert set-x11-keymap us
assert_not_in "KEYMAP=" "$(cat /etc/vconsole.conf)"
assert_in "VC Keymap: .unset." "$(localectl)"
if [[ -f /etc/default/keyboard ]]; then
assert_eq "$(cat /etc/default/keyboard)" "XKBLAYOUT=us"
else
output=$(cat /etc/X11/xorg.conf.d/00-keyboard.conf)
assert_in 'Option "XkbLayout" "us"' "$output"
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 'XKBLAYOUT=us' "$output"
assert_not_in 'XKBMODEL=' "$output"
assert_not_in 'XKBVARIANT=' "$output"
assert_not_in 'XKBOPTIONS=' "$output"
fi
output=$(localectl)
assert_in "X11 Layout: us" "$output"
assert_not_in "X11 Model:" "$output"
assert_not_in "X11 Variant:" "$output"
assert_not_in "X11 Options:" "$output"
# set x11 keymap (layout, model) with conversion
assert_rc 0 localectl set-x11-keymap us
assert_in "KEYMAP=us" "$(cat /etc/vconsole.conf)"
assert_in "VC Keymap: us" "$(localectl)"
if [[ -f /etc/default/keyboard ]]; then
assert_eq "$(cat /etc/default/keyboard)" "XKBLAYOUT=us"
else
output=$(cat /etc/X11/xorg.conf.d/00-keyboard.conf)
assert_in 'Option "XkbLayout" "us"' "$output"
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 'XKBLAYOUT=us' "$output"
assert_not_in 'XKBMODEL=' "$output"
assert_not_in 'XKBVARIANT=' "$output"
assert_not_in 'XKBOPTIONS=' "$output"
fi
output=$(localectl)
assert_in "X11 Layout: us" "$output"
assert_not_in "X11 Model:" "$output"
assert_not_in "X11 Variant:" "$output"
assert_not_in "X11 Options:" "$output"
}
: >/failed
enable_debug
test_locale
test_vc_keymap
test_x11_keymap
test_convert
touch /testok
rm /failed